Back to skill

Security audit

clawrtc

Security checks for vulnerabilities and agentic risk

Overview

ClawRTC is mostly coherent as a crypto-mining and hardware-attestation tool, but it under-discloses telemetry and device identifiers and has unsafe wallet/service handling that users should review before installing.

Review this carefully before installing. It is a token miner that can run continuously, use CPU, create wallet files, contact external services, and optionally install a user-level background service. The main risks are privacy from hostname/MAC transmission and silent install telemetry, plus local wallet/service hardening issues; avoid `--service` and private-key export unless you understand those tradeoffs.

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

other

Error
Location
clawrtc/data/miner.py:156
Finding
<![CDATA[Undisclosed Transmission of Hostname and MAC Addresses]]><![CDATA[ ## Vulnerability Details **File Location**: `clawrtc/data/miner.py:156-190`, `clawrtc/data/miner.py:223-250` **Vulnerability Type**: Undisclosed device-identifier collection and transmission **Risk Level**: High ### Vulnerable Code ```python def _get_hw_info(self): """Collect hardware info with auto-detection.""" family, arch = self._detect_arch() hw = { "platform": platform.system(), "machine": platform.machine(), "hostname": socket.gethostname(), "family": family, "arch": arch, } # Get CPU cpu = self._run_cmd("lscpu | grep 'Model name' | cut -d: -f2 | xargs") hw["cpu"] = cpu or "Unknown" # Get cores cores = self._run_cmd("nproc") hw["cores"] = int(cores) if cores else 6 # Get memory mem = self._run_cmd("free -g | grep Mem | awk '{print $2}'") hw["memory_gb"] = int(mem) if mem else 32 # Get MACs (ensures PoA signal uses real hardware data) macs = self._get_mac_addresses() hw["macs"] = macs hw["mac"] = macs[0] self.hw_info = hw return hw ``` ```python attestation = { "miner": self.wallet, "miner_id": f"claw-{self.hw_info['hostname']}", "nonce": nonce, "report": { "nonce": nonce, "commitment": hashlib.sha256( (nonce + self.wallet + json.dumps(entropy, sort_keys=True)).encode() ).hexdigest(), "derived": entropy, "entropy_score": entropy.get("variance_ns", 0.0) }, "device": { "family": self.hw_info["family"], "arch": self.hw_info["arch"], "model": self.hw_info.get("cpu", "Unknown"), "cpu": self.hw_info["cpu"], "cores": self.hw_info["cores"], "memory_gb": self.hw_info["memory_gb"] }, "signals": { "macs": self.hw_info.get("macs", [self.hw_info["mac"]]), "hostname": self.hw_info["hostname"] }, "fingerprint": self.fingerprint_data if self.fingerprint_data else None } resp = request ...[truncated 2065 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove raw hostname and MAC addresses from the network payload. - Use an ephemeral identifier or a locally generated random device identifier that is not derived from hardware addresses. - If stable proof is essential, transmit a keyed or salted commitment whose salt is not shared across unrelated services. - Minimize the payload to only the measurements required to validate an attestation. - Explicitly disclose every collected and transmitted field, its purpose, retention period, and destination before mining begins. - Add a payload-preview mode and a user-controlled option to disable stable identifiers. - Document deletion and retention policies for attestation records. ]]>

other

Warning
Location
clawrtc/cli.py:319
Finding
<![CDATA[Undisclosed Installation Telemetry Sent to a Third Party]]><![CDATA[ ## Vulnerability Details **File Location**: `clawrtc/cli.py:319-340` **Vulnerability Type**: Undisclosed telemetry and privacy data transmission **Risk Level**: Medium ### Vulnerable Code ```python # Anonymous install telemetry — non-blocking, fails silently, no PII try: import threading, urllib.request def _ping(): try: payload = json.dumps({ "package": "clawrtc", "version": __version__, "platform": platform.system(), "arch": platform.machine(), "source": "pip" }).encode() req = urllib.request.Request( "https://bottube.ai/api/telemetry/install", data=payload, headers={"Content-Type": "application/json"} ) urllib.request.urlopen(req, timeout=5) except Exception: pass threading.Thread(target=_ping, daemon=True).start() except Exception: pass ``` ### Technical Analysis A successful `clawrtc install` launches a background thread that sends package version, operating-system platform, processor architecture, and installation source to `bottube.ai`. The receiving server also necessarily observes normal connection metadata such as source address and request time. This behavior is not presented in the installation consent disclosure. It directly conflicts with the statements in `SKILL.md` that there is “No post-install telemetry” and with the CLI disclosure stating that no data is sent to a third party and that data is sent only to the RustChain node. The nested broad exception handlers suppress all failures and prevent users from observing whether the request was attempted or accepted. ### Attack Path 1. A user reviews the consent disclosure, which identifies only the RustChain node as a data recipient. 2. The user approves installation. 3. After installation, the CLI silently creates a daemon thread. 4. The thread posts ...[truncated 503 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove the telemetry request unless it is necessary for core functionality. - If telemetry is retained, make it disabled by default and require explicit, informed opt-in consent. - Disclose the exact destination, fields, purpose, retention policy, and ability to revoke consent. - Provide a persistent configuration setting such as `telemetry_enabled = false`. - Do not suppress all telemetry errors; log an auditable, non-sensitive status when a request is made. - Update `SKILL.md`, README documentation, and CLI disclosures so they accurately describe runtime behavior. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
clawrtc/cli.py:735
Finding
<![CDATA[Private Wallet Exports Are Created Without Restrictive Permissions]]><![CDATA[ ## Vulnerability Details **File Location**: `clawrtc/cli.py:735-750` **Vulnerability Type**: Insecure storage of cryptographic private keys **Risk Level**: High ### Vulnerable Code ```python export_path = getattr(args, "output", None) or f"rtc-wallet-{wallet['address']}.json" # Remove private key from export if --public-only if getattr(args, "public_only", False): export_data = {k: v for k, v in wallet.items() if k != "private_key"} else: export_data = wallet with open(export_path, "w") as f: json.dump(export_data, f, indent=2) print(f"\n {GREEN}Wallet exported to:{NC} {export_path}") if not getattr(args, "public_only", False): print(f" {RED}Contains private key — keep this file secure!{NC}") ``` ### Technical Analysis The default export contains the wallet's raw Ed25519 private key. Unlike the primary wallet file, which is explicitly changed to mode `0600`, the exported file receives permissions determined by the process umask. On a common `0022` umask, the result may be readable by other local users. The file is also opened with ordinary truncating semantics. The implementation does not reject symbolic links, use exclusive creation, or safely handle replacement of an existing file. Consequently, a predictable export path can be redirected through a symlink or overwrite an existing file writable by the user. ### Attack Path 1. A user runs `clawrtc wallet export` without `--public-only`. 2. The complete wallet object, including `private_key`, is written to the selected or default path. 3. The operating system applies the user's normal umask rather than an enforced private mode. 4. Another local account or process reads the export if its permissions allow access. 5. The attacker reconstructs the Ed25519 private key and uses it to authorize wallet operations. 6. Alternatively, an attacker who can prepare the destination directory creates a symlink at the expected filename, causing the export operation to follow it. ### Impac ...[truncated 306 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Create private-key exports atomically with owner-only mode `0600`. - Use `os.open()` with `O_CREAT | O_EXCL | O_WRONLY` and, where supported, `O_NOFOLLOW`. - Refuse to overwrite an existing file unless the user provides a separate explicit option. - Verify that the destination is a regular file and not a symbolic link. - Default to public-only export and require an explicit `--include-private-key` option for sensitive exports. - Consider encrypting private-key exports using a user-supplied passphrase and a modern authenticated encryption scheme. - Apply restrictive permissions to the destination directory as well as the file. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
clawrtc/data/miner.py:329
Finding
<![CDATA[Predictable Shared Temporary File Permits Symlink-Based File Clobbering]]><![CDATA[ ## Vulnerability Details **File Location**: `clawrtc/data/miner.py:329-332` **Vulnerability Type**: Unsafe temporary-file handling **Risk Level**: Medium ### Vulnerable Code ```python # Save wallet with open("/tmp/local_miner_wallet.txt", "w") as f: f.write(self.wallet) print(f"💾 Wallet saved to: /tmp/local_miner_wallet.txt\n") ``` ### Technical Analysis The miner writes its wallet identifier to a fixed path in the globally shared `/tmp` directory. It uses normal `open(..., "w")` behavior without exclusive creation, symlink protection, ownership validation, or an explicit permission mode. On systems where `/tmp` is shared between users, an attacker can predict the filename and create a symbolic link before the miner starts. The miner then follows that link and truncates or overwrites the target using the victim user's privileges. The file may also expose the wallet identifier according to the process umask. Although the wallet identifier is not itself the private key, it is account-related data and does not need to be duplicated in a shared temporary directory. ### Attack Path 1. A local attacker predicts `/tmp/local_miner_wallet.txt`. 2. Before the victim starts mining, the attacker creates that path as a symbolic link to a file writable by the victim. 3. The victim starts the miner. 4. Python follows the symbolic link when opening the path with write-and-truncate mode. 5. The target file is truncated and replaced with the victim's wallet identifier. 6. Alternatively, another local process reads or modifies the temporary wallet file and interferes with miner instances. ### Impact Assessment The attacker can overwrite or truncate files accessible to the victim account and may learn the wallet identifier. The operation does not allow writing to files that the victim account itself cannot modify, so the scope is the miner user's existing filesystem privileges. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Do not store the wallet identifier in `/tmp`; reuse the protected file under `~/.clawrtc`. - If temporary storage is unavoidable, use `tempfile.NamedTemporaryFile` or `mkstemp`. - Create files with exclusive semantics and mode `0600`. - Use no-follow behavior and verify the resulting file descriptor refers to a regular file owned by the current user. - Remove temporary state promptly after use. - Avoid a single global filename when concurrent miner instances may run. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
clawrtc/cli.py:377
Finding
<![CDATA[Wallet Input Can Inject Persistent Service Configuration]]><![CDATA[ ## Vulnerability Details **File Location**: `clawrtc/cli.py:377-449` **Vulnerability Type**: Persistent service configuration injection **Risk Level**: High ### Vulnerable Code ```python def _setup_systemd(wallet): """Set up systemd user service on Linux.""" service_dir = os.path.expanduser("~/.config/systemd/user") os.makedirs(service_dir, exist_ok=True) service_file = os.path.join(service_dir, "clawrtc-miner.service") python_bin = os.path.join(VENV_DIR, "bin", "python") miner_py = os.path.join(INSTALL_DIR, "miner.py") with open(service_file, "w") as f: f.write(textwrap.dedent(f"""\ [Unit] Description=ClawRTC RTC Miner — AI Agent Mining After=network-online.target Wants=network-online.target [Service] ExecStart={python_bin} {miner_py} --wallet {wallet} Restart=always RestartSec=30 WorkingDirectory={INSTALL_DIR} Environment=PYTHONUNBUFFERED=1 [Install] WantedBy=default.target """)) try: run_cmd("systemctl --user daemon-reload") run_cmd("systemctl --user enable clawrtc-miner") run_cmd("systemctl --user start clawrtc-miner") success("Service installed and started (auto-restarts on reboot)") except Exception: warn("Systemd user services not available. Use: clawrtc start") ``` ```python with open(plist_file, "w") as f: f.write(textwrap.dedent(f"""\ ... <key>ProgramArguments</key> <array> <string>{python_bin}</string> <string>{miner_py}</string> <string>--wallet</string> <string>{wallet}</string> </array> ... """)) try: run_cmd(f'launchctl unload "{plist_file}" 2>/dev/null', check=False) run_cmd(f'launchctl load "{plist_file}"') ``` ### Technical Analysis The wallet value originates from the `--wallet` command-l ...[truncated 2101 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Define and enforce a strict wallet format, such as an approved address pattern or a conservative identifier character set. - Reject newline, carriage-return, NUL, control characters, whitespace, and service/XML metacharacters. - XML-escape every value inserted into a launchd property list, preferably by using a proper plist serialization library. - Generate systemd units through a safe structured mechanism and keep attacker-controlled values out of directive lines. - Store the wallet in a protected configuration file and have the miner read it at runtime rather than embedding it in the unit. - Validate the completed unit or property list before loading it. - Require explicit confirmation showing the exact service command before enabling persistence. - Ensure uninstall disables and unloads the service before removing its configuration. ]]>

T08 · Insecure Dependencies

Warning
Location
clawrtc/cli.py:271
Finding
<![CDATA[Runtime Installation Uses Mutable Unpinned Dependencies]]><![CDATA[ ## Vulnerability Details **File Location**: `clawrtc/cli.py:271-280` **Vulnerability Type**: Unsafe dependency installation and supply-chain exposure **Risk Level**: Medium ### Vulnerable Code ```python # Create venv if not os.path.isdir(VENV_DIR): log("Creating Python environment...") run_cmd(f'"{sys.executable}" -m venv "{VENV_DIR}"') # Install deps log("Installing dependencies...") pip = os.path.join(VENV_DIR, "bin", "pip") run_cmd(f'"{pip}" install --upgrade pip -q') run_cmd(f'"{pip}" install requests -q') success("Dependencies ready") ``` ### Technical Analysis The install command upgrades pip to the latest version and installs `requests` without an exact version or package hash. The effective code installed into `~/.clawrtc/venv` can therefore change over time even when the reviewed ClawRTC version remains unchanged. The selected package name is legitimate and there is no evidence in the reviewed project that it intentionally installs a typosquatted dependency. Nevertheless, mutable resolution from the user's configured package index creates supply-chain exposure. A compromised index, dependency account, package release, or custom index configuration could cause unreviewed code to be installed and later imported by the miner. The shell command uses internally constructed paths rather than direct external input in this location, so the primary issue is dependency integrity rather than demonstrated shell injection. ### Attack Path 1. A user approves `clawrtc install`. 2. The CLI creates a virtual environment. 3. It downloads the latest available pip from the configured Python package index. 4. It resolves and installs an unconstrained version of `requests` and its transitive dependencies. 5. If the selected source or package release is compromised, malicious installation or import-time code is placed in the miner environment. 6. The miner imports `requests`, causing the compromised component to run with the user's privileges. ## ...[truncated 362 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Pin exact audited versions of direct and transitive dependencies. - Use a lock file and require cryptographic hashes during installation. - Avoid automatically upgrading pip as part of the application installation flow. - Reuse dependencies installed through normal package metadata instead of creating a second mutable environment. - If isolation is required, ship a reviewed lock file and install with hash verification. - Document the package index used and warn when custom or untrusted indexes are configured. - Add automated dependency vulnerability and provenance scanning to the release process. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Memory PoisoningPersistent Context Injection, Context Window Stuffing, Memory Manipulation
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
Findings (61)

Tool Parameter Abuse

High
Category
Tool Misuse
Content
def run_cmd(cmd, check=True, capture=False):
    """Run a shell command."""
    try:
        result = subprocess.run(
            cmd, shell=True, check=check,
            capture_output=capture, text=True
        )
Confidence
99% confidence
Finding
Using shell=True in a generic command wrapper significantly increases the attack surface because any interpolated parameter can become shell syntax. In this file, that wrapper is used for service-management and environment-setup commands, and some inputs such as wallet values are user-controlled, making command injection plausible in an agent or automated installation context.

Intent-Code Divergence

High
Confidence
99% confidence
Finding
The consent disclosure states that no data is sent to any third party, but the code later posts telemetry to bottube.ai. Misrepresenting data flows is dangerous because it defeats user consent and can hide privacy-impacting behavior behind reassuring text.

Tainted flow: 'req' from open (line 720, file read) → urllib.request.urlopen (network output)

High
Category
Data Flow
Content
try:
        import urllib.request
        req = urllib.request.Request(f"{NODE_URL}/api/miners")
        with urllib.request.urlopen(req, timeout=10) as resp:
            miners = json.loads(resp.read())
            log(f"Active miners on network: {len(miners)}")
    except Exception:
Confidence
80% confidence
Finding
File contents flow to a network sink. This may indicate data exfiltration of sensitive files.

Tainted flow: 'req' from open (line 720, file read) → urllib.request.urlopen (network output)

High
Category
Data Flow
Content
try:
        import urllib.request
        req = urllib.request.Request(f"{NODE_URL}/api/miners")
        with urllib.request.urlopen(req, timeout=10) as resp:
            miners = json.loads(resp.read())
            log(f"Active miners on network: {len(miners)}")
    except Exception:
Confidence
80% confidence
Finding
File contents flow to a network sink. This may indicate data exfiltration of sensitive files.

Tainted flow: 'req' from open (line 720, file read) → urllib.request.urlopen (network output)

High
Category
Data Flow
Content
try:
        import urllib.request
        req = urllib.request.Request(f"{NODE_URL}/api/miners")
        with urllib.request.urlopen(req, timeout=10) as resp:
            miners = json.loads(resp.read())
            log(f"Active miners on network: {len(miners)}")
    except Exception:
Confidence
80% confidence
Finding
File contents flow to a network sink. This may indicate data exfiltration of sensitive files.

Tainted flow: 'req' from open (line 720, file read) → urllib.request.urlopen (network output)

High
Category
Data Flow
Content
data=payload,
                    headers={"Content-Type": "application/json"}
                )
                urllib.request.urlopen(req, timeout=5)
            except Exception:
                pass
        threading.Thread(target=_ping, daemon=True).start()
Confidence
99% confidence
Finding
The installer silently sends install telemetry to a third-party domain in a background thread without opt-in, while the disclosure text claims no data is sent to any third party. Even if the payload omits obvious PII, it still leaks installation metadata externally and undermines informed consent.

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Content
wallet = open(wallet_file).read().strip() if os.path.exists(wallet_file) else ""
    log(f"Starting miner in foreground (Ctrl+C to stop)...")
    log(f"Tip: Use 'clawrtc start --service' for background auto-restart")
    os.execvp(python_bin, [python_bin, miner_py] + (["--wallet", wallet] if wallet else []))


def cmd_stop(args):
Confidence
85% confidence
Finding
os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Content
if system == "Linux":
        sf = os.path.expanduser("~/.config/systemd/user/clawrtc-miner.service")
        if os.path.exists(sf):
            os.execlp("journalctl", "journalctl", "--user", "-u", "clawrtc-miner", "-f", "--no-pager", "-n", "50")
        else:
            log_file = os.path.join(INSTALL_DIR, "miner.log")
            if os.path.exists(log_file):
Confidence
85% confidence
Finding
os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Content
else:
            log_file = os.path.join(INSTALL_DIR, "miner.log")
            if os.path.exists(log_file):
                os.execlp("tail", "tail", "-f", log_file)
            else:
                warn("No logs found. Start the miner first: clawrtc start")
    elif system == "Darwin":
Confidence
85% confidence
Finding
os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Content
else:
            log_file = os.path.join(INSTALL_DIR, "miner.log")
            if os.path.exists(log_file):
                os.execlp("tail", "tail", "-f", log_file)
            else:
                warn("No logs found. Start the miner first: clawrtc start")
    elif system == "Darwin":
Confidence
85% confidence
Finding
os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

Memory Manipulation

High
Category
Memory Poisoning
Content
def coinbase_swap_info(args):
    """Show USDC→wRTC swap instructions and Aerodrome pool info."""
    print(f"""
  {GREEN}{BOLD}USDC → wRTC Swap Guide{NC}
Confidence
85% confidence
Finding
Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

External Script Fetching

High
Category
Supply Chain
Content
5. Bridge wRTC to native RTC at https://bottube.ai/bridge

  {DIM}Or use the RustChain API:{NC}
    curl -s https://bulbous-bouffant.metalseed.net/wallet/swap-info
""")
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
def _run_cmd(self, cmd):
        try:
            return subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                                text=True, timeout=10, shell=True).stdout.strip()
        except:
            return ""
Confidence
98% confidence
Finding
Using subprocess.run with shell=True is a classic unsafe execution pattern because the shell interprets metacharacters, expansions, and pipelines. In an agent skill, this is especially risky since future parameter reuse, refactoring, or indirect control paths can turn seemingly harmless hardware queries into arbitrary command execution.

Missing User Warnings

High
Confidence
99% confidence
Finding
The attestation payload sends hardware characteristics, hostname, MAC addresses, entropy-derived fingerprints, and optional fingerprint-check results to a remote third-party node. This creates device tracking and privacy risk, and in an agent setting is more dangerous because users may invoke the skill expecting local analysis rather than exfiltration of stable identifiers.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The README explicitly states that the agent performs hardware fingerprinting and automatic recurring attestation to a network, but it does not clearly disclose what device characteristics are collected, what is transmitted, how often it is sent, how long it is retained, or who can access it. In an agent-installation context, this is dangerous because users may authorize persistent background telemetry and uniquely identifying device data without informed consent, enabling privacy loss, tracking, and unexpected outbound communication.

Session Persistence

Medium
Category
Rogue Agent
Content
Usage:
    pip install clawrtc
    clawrtc wallet create          Generate your RTC address
    clawrtc install --wallet RTC...
    clawrtc start
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.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def run_cmd(cmd, check=True, capture=False):
    """Run a shell command."""
    try:
        result = subprocess.run(
            cmd, shell=True, check=check,
            capture_output=capture, text=True
        )
Confidence
98% confidence
Finding
The helper uses subprocess.run with shell=True on dynamically constructed command strings throughout the CLI. Several call sites interpolate values derived from user input or files, such as wallet names and plist paths, which creates command injection risk if those values contain shell metacharacters.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
elif system == "Darwin":
        try:
            out = subprocess.run(
                ["sysctl", "-n", "machdep.cpu.features"],
                capture_output=True, text=True
            ).stdout.lower()
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
The disclosure says 'No external downloads — all code ships with the package,' yet installation performs pip upgrades and installs requests from external package sources. This is misleading and materially affects the trust and supply-chain risk profile presented to users.

Session Persistence

Medium
Category
Rogue Agent
Content
wallet = f"claw-{hostname}-{int(time.time()) % 100000}"
        warn(f"No wallet name provided. Auto-generated: {wallet}")

    # Create install dir
    log(f"Installing to {INSTALL_DIR}")
    os.makedirs(INSTALL_DIR, exist_ok=True)
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.

Session Persistence

Medium
Category
Rogue Agent
Content
try:
        run_cmd("systemctl --user daemon-reload")
        run_cmd("systemctl --user enable clawrtc-miner")
        run_cmd("systemctl --user start clawrtc-miner")
        success("Service installed and started (auto-restarts on reboot)")
    except Exception:
Confidence
80% 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.

Session Persistence

Medium
Category
Rogue Agent
Content
def _setup_launchd(wallet):
    """Set up launchd agent on macOS."""
    plist_dir = os.path.expanduser("~/Library/LaunchAgents")
    os.makedirs(plist_dir, exist_ok=True)
    plist_file = os.path.join(plist_dir, "com.clawrtc.miner.plist")
    python_bin = os.path.join(VENV_DIR, "bin", "python")
Confidence
75% 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.

Session Persistence

Medium
Category
Rogue Agent
Content
def _setup_launchd(wallet):
    """Set up launchd agent on macOS."""
    plist_dir = os.path.expanduser("~/Library/LaunchAgents")
    os.makedirs(plist_dir, exist_ok=True)
    plist_file = os.path.join(plist_dir, "com.clawrtc.miner.plist")
    python_bin = os.path.join(VENV_DIR, "bin", "python")
Confidence
75% 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.

Session Persistence

Medium
Category
Rogue Agent
Content
def _setup_launchd(wallet):
    """Set up launchd agent on macOS."""
    plist_dir = os.path.expanduser("~/Library/LaunchAgents")
    os.makedirs(plist_dir, exist_ok=True)
    plist_file = os.path.join(plist_dir, "com.clawrtc.miner.plist")
    python_bin = os.path.join(VENV_DIR, "bin", "python")
Confidence
75% 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.

Session Persistence

Medium
Category
Rogue Agent
Content
def _setup_launchd(wallet):
    """Set up launchd agent on macOS."""
    plist_dir = os.path.expanduser("~/Library/LaunchAgents")
    os.makedirs(plist_dir, exist_ok=True)
    plist_file = os.path.join(plist_dir, "com.clawrtc.miner.plist")
    python_bin = os.path.join(VENV_DIR, "bin", "python")
Confidence
75% 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.

Static analysis

No suspicious patterns detected.