Back to skill

Security audit

0602-tosr2-07

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its stock-analysis purpose, but its optional X/Twitter scanning handles live session credentials in an overbroad and risky way.

Review this before installing if you plan to use X/Twitter features. Avoid placing live X cookies in the skill directory, prefer --no-social, run the skill in an environment without unrelated secrets, and be aware that portfolio and watchlist data are stored locally as JSON. Treat all financial outputs as informational, not trading instructions.

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

T08 · Insecure Dependencies

Warning
Location
README.md:143
Finding

Unpinned globally installed CLI creates a supply-chain execution risk

Content
View full analysis

Vulnerability Details

File Location: README.md:143-150; also documented in SKILL.md:150-154
Vulnerability Type: Unpinned third-party dependency with access to authentication credentials
Risk Level: Medium

Vulnerable Code and Instructions

markdown
### Twitter/X Setup (Optional)

1. Install bird CLI: `npm install -g @steipete/bird`
2. Login to x.com in Safari/Chrome
3. Create `.env` file:

AUTH_TOKEN=your_auth_token CT0=your_ct0_token

text

Technical Analysis

The installation command retrieves and globally installs the latest version of @steipete/bird without an exact version, lockfile, or integrity constraint. npm installation may execute package lifecycle scripts with the privileges of the installing user. The installed program is subsequently invoked with authenticated X session credentials.

The social-media integration is consistent with the declared functionality, but using an unpinned global package is not the minimum-risk implementation. The package's effective code can change after this Skill has been reviewed.

No evidence shows that the current package is malicious. The vulnerability is the avoidable trust placed in mutable registry content and its transitive dependencies.

Attack Path

  1. An attacker compromises the package publisher, npm account, package distribution channel, or a transitive dependency.
  2. A malicious release becomes the latest version associated with @steipete/bird.
  3. A user follows the documentation and runs npm install -g @steipete/bird.
  4. Malicious installation lifecycle code or runtime code executes as the user.
  5. When the scanner invokes the CLI, the compromised program can access the inherited environment, including X session credentials and potentially unrelated secrets.
  6. The attacker can exfiltrate those credentials or perform other actions available to the local user.

Impact Assessment

Successful exploitation cou ...[truncated 369 chars]

Remediation
View remediation

Remediation Suggestions

  1. Pin the CLI to an exact, reviewed version rather than installing the latest release.
  2. Record and verify package integrity metadata and use a lockfile where possible.
  3. Avoid global installation. Install the package in a dedicated, isolated directory or container with minimal filesystem access.
  4. Document the verified upstream repository, expected package identity, review process, and secure update procedure.
  5. Disable package lifecycle scripts during installation where compatible with the dependency.
  6. Prefer an official, scoped, read-only API integration over a browser-session CLI.
  7. Combine dependency pinning with a minimal subprocess environment so a compromised dependency cannot access unrelated credentials.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/hot_scanner.py:387
Finding

External social-media CLI receives the entire process environment

Content
View full analysis

Vulnerability Details

File Location: scripts/hot_scanner.py:387-392; scripts/rumor_scanner.py:79-81; scripts/rumor_scanner.py:132-134
Vulnerability Type: Excessive credential exposure to a third-party subprocess
Risk Level: Medium

Vulnerable Code

scripts/hot_scanner.py:

python
env = os.environ.copy()
result = subprocess.run(
    [bird_bin, "search", query, "-n", "15", "--json"],
    capture_output=True, text=True, timeout=30, env=env
)

scripts/rumor_scanner.py:

python
cmd = [BIRD_CLI, 'search', query, '-n', '10', '--json']
env = os.environ.copy()

result = subprocess.run(cmd, capture_output=True, text=True, timeout=30, env=env)

The same pattern is repeated for general social-media buzz searches:

python
cmd = [BIRD_CLI, 'search', query, '-n', '15', '--json']
env = os.environ.copy()

result = subprocess.run(cmd, capture_output=True, text=True, timeout=30, env=env)

Technical Analysis

The child process requires a limited set of authentication and runtime variables, but the scripts copy and forward every environment variable available to the parent process. Depending on the host, this may include cloud credentials, API keys, CI/CD secrets, database passwords, proxy credentials, and tokens unrelated to stock analysis.

This violates least privilege. A subprocess always has access to the environment passed to it, even when those variables are not used for the intended operation.

In hot_scanner.py, the executable search eventually falls back to the generic name bird. That name can be resolved through PATH, so a malicious or incorrectly installed executable can receive all inherited variables.

Attack Path

  1. The Agent or user runs the scanner in an environment containing sensitive variables.
  2. An attacker compromises the installed bird package, replaces its executable, or places a malicious bird earlier in the executable search pa ...[truncated 861 chars]
Remediation
View remediation

Remediation Suggestions

  1. Construct an explicit minimal child environment instead of copying os.environ:
python
child_env = {
    "PATH": trusted_path,
    "AUTH_TOKEN": auth_token,
    "CT0": ct0,
    "LANG": os.environ.get("LANG", "C.UTF-8"),
}
  1. Pass only variables strictly required by the reviewed CLI.
  2. Resolve the executable to a trusted absolute path and verify ownership and permissions before execution.
  3. Remove the fallback to an unverified PATH-resolved bird, or use shutil.which followed by validation against an approved installation directory.
  4. Run the social-media client in an isolated process or container without access to unrelated files and credentials.
  5. Prefer short-lived, read-only API credentials over reusable browser-session cookies.
  6. Add tests that assert unrelated environment variables are absent from the subprocess environment.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/hot_scanner.py:22
Finding

Reusable X browser-session credentials are loaded from a plaintext project file

Content
View full analysis

Vulnerability Details

File Location: scripts/hot_scanner.py:22-30; scripts/rumor_scanner.py:30-38; credential setup documented at README.md:143-154 and SKILL.md:150-154
Vulnerability Type: Plaintext sensitive credential storage and unrestricted environment mutation
Risk Level: Medium

Vulnerable Code

scripts/hot_scanner.py:

python
# Load .env file if exists
ENV_FILE = Path(__file__).parent.parent / ".env"
if ENV_FILE.exists():
    with open(ENV_FILE) as f:
        for line in f:
            line = line.strip()
            if line and not line.startswith("#") and "=" in line:
                key, value = line.split("=", 1)
                os.environ[key] = value

scripts/rumor_scanner.py:

python
BIRD_ENV = Path(__file__).parent.parent / ".env"

def load_env():
    """Load environment variables from .env file."""
    if BIRD_ENV.exists():
        for line in BIRD_ENV.read_text().splitlines():
            if '=' in line and not line.startswith('#'):
                key, value = line.split('=', 1)
                os.environ[key.strip()] = value.strip().strip('"').strip("'")

The documentation directs users to place reusable browser cookies in that file:

text
AUTH_TOKEN=your_auth_token
CT0=your_ct0_token

Technical Analysis

The Skill instructs users to copy authenticated X cookies from browser developer tools into a plaintext .env located at the project root. These values represent reusable session credentials and may permit operations beyond read-only trend retrieval.

The code does not verify file ownership or require restrictive permissions such as mode 0600. It also imports every key/value pair from the file into the global process environment rather than limiting loading to AUTH_TOKEN and CT0.

A project-level secret file is also more likely to be included accidentally in source-control commits, archives, backups, diagnosti ...[truncated 1173 chars]

Remediation
View remediation

Remediation Suggestions

  1. Prefer official OAuth or API credentials with read-only scope and short expiration.
  2. Store credentials in the operating system's credential manager or an established secret-management service.
  3. If file storage is unavoidable, place the file outside the project directory and require mode 0600.
  4. Verify that the credential file is owned by the current user and reject symlinks or insecure permissions.
  5. Load only the expected AUTH_TOKEN and CT0 keys rather than arbitrary entries.
  6. Do not mutate the global environment; pass narrowly scoped credentials directly to the required subprocess.
  7. Add .env to source-control ignore rules and provide an .env.example containing placeholders only.
  8. Document credential revocation, rotation, session termination, and incident-response procedures.

T09 · Insecure Skill Coding Practices

Note
Location
scripts/portfolio.py:111
Finding

Portfolio and watchlist financial data are stored without explicit private permissions

Content
View full analysis

Vulnerability Details

File Location: scripts/portfolio.py:42-48 and scripts/portfolio.py:111-118; scripts/watchlist.py:57-77
Vulnerability Type: Sensitive local data stored with ambient filesystem permissions
Risk Level: Low

Vulnerable Code

scripts/portfolio.py:

python
def get_storage_path() -> Path:
    """Get the portfolio storage path."""
    # Use ~/.clawdbot/skills/stock-analysis/portfolios.json
    state_dir = os.environ.get("CLAWDBOT_STATE_DIR", os.path.expanduser("~/.clawdbot"))
    portfolio_dir = Path(state_dir) / "skills" / "stock-analysis"
    portfolio_dir.mkdir(parents=True, exist_ok=True)
    return portfolio_dir / "portfolios.json"
python
# Ensure directory exists
self.path.parent.mkdir(parents=True, exist_ok=True)

# Atomic write: write to temp file, then rename
tmp_path = self.path.with_suffix(".tmp")
try:
    with open(tmp_path, "w", encoding="utf-8") as f:
        json.dump(self._data, f, indent=2)
    tmp_path.replace(self.path)

scripts/watchlist.py:

python
def ensure_dirs():
    """Create storage directories."""
    WATCHLIST_DIR.mkdir(parents=True, exist_ok=True)
python
def save_watchlist(items: list[WatchlistItem]):
    """Save watchlist to file."""
    ensure_dirs()
    data = [asdict(item) for item in items]
    WATCHLIST_FILE.write_text(json.dumps(data, indent=2))

Technical Analysis

Portfolio records contain asset symbols, quantities, and cost bases. Watchlist records may contain target prices, stop prices, signal history, and free-form notes. These are sensitive financial and behavioral data.

Directories and files are created using permissions derived from the current process umask. The code does not enforce mode 0700 for directories or 0600 for data files. A custom CLAWDBOT_STATE_DIR may also point to a shared or incorrectly owned location.

The portfolio implementation correct ...[truncated 1070 chars]

Remediation
View remediation

Remediation Suggestions

  1. Create the state directory with mode 0700.
  2. Create portfolio, watchlist, and temporary files with mode 0600.
  3. After atomic replacement, explicitly enforce mode 0600 on the destination.
  4. Validate that the storage directory and existing files are owned by the current user.
  5. Reject symlinks and unsafe shared locations where appropriate.
  6. Validate a custom CLAWDBOT_STATE_DIR before reading or writing sensitive data.
  7. Consider optional encryption at rest for portfolio and note fields.
  8. Document that scan cache files can contain collected social content and should also use private permissions where confidentiality is desired.
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
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
Findings (54)

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · App-Plan.md (reported line 114)May include surrounding context.

md
GET  /portfolios
   POST /portfolios
   PUT  /portfolios/{id}
   DELETE /portfolios/{id}

   GET  /portfolios/{id}/assets
   POST /portfolios/{id}/assets

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · App-Plan.md (reported line 119)May include surrounding context.

md
GET  /portfolios/{id}/assets
   POST /portfolios/{id}/assets
   PUT  /portfolios/{id}/assets/{ticker}
   DELETE /portfolios/{id}/assets/{ticker}

   GET  /portfolios/{id}/performance?period=weekly
   GET  /portfolios/{id}/summary

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · App-Plan.md (reported line 126)May include surrounding context.

md
GET  /alerts
   POST /alerts
   DELETE /alerts/{id}

   GET  /user/subscription
   POST /user/subscription/upgrade

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

Declaring watchlists, alerts, dividend analysis, scoring, trend scanning, and rumor detection without clear implementation, while also implying local persistent storage, can cause users to rely on controls or analyses that do not exist. In a finance-oriented skill, this is especially risky because users may make decisions or approve automation under false assumptions about data handling and analytical rigor.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

Declaring watchlists, alerts, dividend analysis, scoring, trend scanning, and rumor detection without clear implementation, while also implying local persistent storage, can cause users to rely on controls or analyses that do not exist. In a finance-oriented skill, this is especially risky because users may make decisions or approve automation under false assumptions about data handling and analytical rigor.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

Declaring watchlists, alerts, dividend analysis, scoring, trend scanning, and rumor detection without clear implementation, while also implying local persistent storage, can cause users to rely on controls or analyses that do not exist. In a finance-oriented skill, this is especially risky because users may make decisions or approve automation under false assumptions about data handling and analytical rigor.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

Declaring watchlists, alerts, dividend analysis, scoring, trend scanning, and rumor detection without clear implementation, while also implying local persistent storage, can cause users to rely on controls or analyses that do not exist. In a finance-oriented skill, this is especially risky because users may make decisions or approve automation under false assumptions about data handling and analytical rigor.

Content

No source excerpt is available for this finding.

Self-Modification

High
Category
Rogue Agent
Confidence
85% confidence
Finding

Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Content

Scanner excerpt · TODO.md (reported line 88)May include surrounding context.

md
- [ ] Add timeout per indicator (10s max)
- [ ] Test with multiple stocks in sequence
- [ ] Measure actual runtime improvement
- [ ] Update SKILL.md with new runtime (target: 3-4s)

**Expected Impact**:
- Reduce runtime from 6-10s to 3-4s per stock

Self-Modification

High
Category
Rogue Agent
Confidence
85% confidence
Finding

Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Content

Scanner excerpt · TODO.md (reported line 193)May include surrounding context.

md
- [ ] Add timeout per indicator (10s max)
- [ ] Test with multiple stocks in sequence
- [ ] Measure actual runtime improvement
- [ ] Update SKILL.md with new runtime (target: 3-4s)

**Expected Impact**:
- Reduce runtime from 6-10s to 3-4s per stock

Ssd 3

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill documentation explicitly tells users to extract and use live Twitter/X authentication cookies for automation. Those cookies can enable direct account session reuse, so disclosure or misuse could lead to account takeover, data exposure, unauthorized actions, and bypass of safer supported authentication flows.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
93% confidence
Finding

The documentation tells users to place sensitive Twitter/X session secrets in a .env file inside the skill directory. In practice, project-local secret files are frequently exposed through accidental git commits, backups, shared workspaces, debug output, or permissive filesystem access, especially when the values are live session cookies rather than scoped API keys.

Content

Scanner excerpt · docs/HOT_SCANNER.md (reported line 149)May include surrounding context.

Create .env file in the skill directory:

bash
# /path/to/stock-analysis/.env
AUTH_TOKEN=your_auth_token_here
CT0=your_ct0_token_here

Credential Access

High
Category
Privilege Escalation
Confidence
93% confidence
Finding

Referencing and loading a repository-local .env file gives this script access to secrets unrelated to hot scanning, broadening privilege unnecessarily. While reading .env is common, in this file it becomes security-relevant because those values are later inherited by a subprocess.

Content

Scanner excerpt · scripts/hot_scanner.py (reported line 22)May include surrounding context.

python
from collections import defaultdict
from concurrent.futures import ThreadPoolExecutor, as_completed

# Load .env file if exists
ENV_FILE = Path(__file__).parent.parent / ".env"
if ENV_FILE.exists():
    with open(ENV_FILE) as f:

Credential Access

High
Category
Privilege Escalation
Confidence
93% confidence
Finding

The .env handling indicates this module can access local credentials, which is not inherently unsafe but is unnecessary for most of its scraping logic. Combined with subprocess execution, this increases the chance that locally stored secrets are disclosed to child tooling or logs.

Content

Scanner excerpt · scripts/hot_scanner.py (reported line 23)May include surrounding context.

python
from concurrent.futures import ThreadPoolExecutor, as_completed

# Load .env file if exists
ENV_FILE = Path(__file__).parent.parent / ".env"
if ENV_FILE.exists():
    with open(ENV_FILE) as f:
        for line in f:

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

Invoking an external bird binary for Twitter/X access expands the attack surface beyond normal data retrieval and grants execution to code outside the script's control. In the context of a stock-analysis skill, this is more dangerous because it is not essential to core local analysis and may run attacker-controlled or tampered tooling on the host.

Content

No source excerpt is available for this finding.

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
98% confidence
Finding

os.environ.copy() forwards the full process environment to the external bird subprocess, which can include tokens or credentials loaded from .env. If the child binary is malicious, compromised, or simply over-privileged, it can access and exfiltrate those secrets, making this a concrete credential exposure path.

Content

Scanner excerpt · scripts/hot_scanner.py (reported line 387)May include surrounding context.

python
for category, query in searches:
                try:
                    env = os.environ.copy()
                    result = subprocess.run(
                        [bird_bin, "search", query, "-n", "15", "--json"],
                        capture_output=True, text=True, timeout=30, env=env

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

Referencing a repository-local .env file for credentials is not inherently malicious, but in this script it contributes to a risky flow where secrets are loaded into process environment and later exposed to an external subprocess. The danger comes from how these credentials are handled afterward, not from the path constant alone.

Content

Scanner excerpt · scripts/rumor_scanner.py (reported line 30)May include surrounding context.

python
# Bird CLI path
BIRD_CLI = "/home/clawdbot/.nvm/versions/node/v24.12.0/bin/bird"
BIRD_ENV = Path(__file__).parent.parent / ".env"

def load_env():
    """Load environment variables from .env file."""

Credential Access

High
Category
Privilege Escalation
Confidence
92% confidence
Finding

The code reads all key/value pairs from .env and injects them into os.environ, making every secret available to later subprocesses and any imported code in the same process. In a skill that calls third-party services and external tooling, this significantly increases the chance of accidental credential disclosure.

Content

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

python
BIRD_ENV = Path(__file__).parent.parent / ".env"

def load_env():
    """Load environment variables from .env file."""
    if BIRD_ENV.exists():
        for line in BIRD_ENV.read_text().splitlines():
            if '=' in line and not line.startswith('#'):

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
98% confidence
Finding

Copying the entire environment and handing it to an external binary is a classic credential overexposure pattern. In this script's context, load_env() may have populated secrets from .env, so the Bird CLI receives every available token and configuration variable, not just the one it needs.

Content

Scanner excerpt · scripts/rumor_scanner.py (reported line 79)May include surrounding context.

python
for query in queries[:4]:  # Limit to avoid rate limits
        try:
            cmd = [BIRD_CLI, 'search', query, '-n', '10', '--json']
            env = os.environ.copy()
            
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=30, env=env)

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
98% confidence
Finding

This second os.environ.copy() repeats the same overbroad credential propagation issue on another execution path. Any sensitive variables present in the parent process can be exposed to the Bird CLI and any of its dependencies or telemetry.

Content

Scanner excerpt · scripts/rumor_scanner.py (reported line 132)May include surrounding context.

python
for query in queries[:3]:
        try:
            cmd = [BIRD_CLI, 'search', query, '-n', '15', '--json']
            env = os.environ.copy()
            
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=30, env=env)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The plan explicitly includes Mixpanel/Amplitude product analytics and Sentry error tracking, but the document does not pair those collection behaviors with user-facing notice, consent flow, or retention/minimization controls. In a consumer finance app handling portfolio, subscription, and behavioral data, undisclosed telemetry can create privacy and compliance risk, especially under GDPR/CCPA-style regimes.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The README instructs users to manually extract X/Twitter session tokens from browser cookies and place them in a local .env file, but it does not clearly warn that these are sensitive authentication credentials equivalent to active session material. If users mishandle, commit, share, or log these tokens, an attacker could reuse them to access the user's X account or automate actions under that identity.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill advertises executable commands, network access, shell execution, environment use, and local file read/write behavior, but it does not declare an explicit tool scope such as permissions or allowed-tools. This creates a transparency and governance gap: a host may grant broader capabilities than users expect, increasing the chance of unsafe execution or unintended data access.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The documentation tells users to create a .env file containing Twitter/X authentication tokens for optional bird CLI integration, even though that capability is not central to the stated Yahoo Finance analysis purpose. Encouraging secret placement for a loosely justified optional feature increases credential-exposure risk, especially if the working directory is shared, synced, or later accessed by other tools.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The skill explicitly frames outputs as BUY/HOLD/SELL signals and recommendations but only includes broad disclaimers elsewhere, without strong, context-local warnings about financial risk, uncertainty, delays, and the possibility of loss. In an investment context, that makes overreliance more likely, especially for retail users who may treat the system as authoritative advice.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The documentation is internally inconsistent: it says the system produces clear BUY/HOLD/SELL signals and recommendations, while later claiming it is not providing trading signals. This can mislead users about the nature of the output, reduce appropriate caution, and create unsafe reliance on actionable investment guidance presented as something less consequential.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.