Back to skill

Security audit

Ham Radio DX Monitor

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly does what it claims, but it encourages persistent background monitoring and uses unsafe shared temporary files without enough lifecycle or safety guidance.

Review this carefully before installing. Use manual one-shot commands first, avoid running it as root, and do not add the cron jobs unless you are comfortable with ongoing network connections and local logs. If you do schedule it, move state and logs out of /tmp into a private user-owned directory and add your own cleanup/removal process.

Vulnerability Patterns
  • System PersistenceInstalls backdoors, hooks, services, or scheduled tasks that survive the run
  • 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)

T06 · System Persistence

Warning
Location
SKILL.md:80
Finding
Optional cron configuration creates cross-session persistence## Vulnerability Details **File Location**: `SKILL.md:80-95` **Vulnerability Type**: User-installed recurring scheduled tasks **Risk Level**: Medium ### Vulnerable Code ```cron ### Real-Time Alerts (Check Every 5 Minutes) # Add to crontab */5 * * * * cd ~/clawd && python3 skills/ham-radio-dx/dx-monitor.py watch --new-only --callsign YOUR_CALL >> /tmp/dx-alerts.log ### Daily Digest (9am Every Day) # Add to crontab 0 9 * * * cd ~/clawd && python3 skills/ham-radio-dx/dx-monitor.py digest >> ~/dx-digest-$(date +\%Y-\%m-\%d).txt ``` ### Technical Analysis The documentation instructs users to add two recurring cron entries. These entries survive the original Skill invocation and repeatedly execute the project script under the user's account. Scheduling is relevant to the declared automated-monitoring feature and does not request elevated privileges. However, it exceeds the privileges and persistence required for manual spot monitoring or digest generation. The scheduled commands refer to a mutable script beneath `~/clawd`; any future modification or replacement of that file will be executed automatically by cron. The repository does not silently install these tasks—the user must add them manually—but the documentation does not provide removal instructions, integrity controls, or a warning about the resulting persistent network activity. ### Attack Path 1. A user follows the documentation and adds one or both entries to their crontab. 2. The scheduled task continues running after the original interactive session ends. 3. The script or one of its parent directories is subsequently modified by another process, compromised account, unsafe update, or malicious package. 4. Cron executes the modified script every five minutes or once daily with the user's permissions. 5. The replacement code gains recurring execution and access to resources available to that user. ### Impact Assessment E ...[truncated 564 chars]
Remediation
## Remediation Suggestions - Keep scheduled monitoring explicitly opt-in and separate from basic installation. - Explain that the entries persist across sessions and repeatedly initiate outbound connections. - Show users the exact crontab changes and request confirmation before any automated installer applies them. - Run the task under a dedicated, unprivileged account where practical. - Use an absolute, access-controlled script path rather than a mutable working-tree-relative path. - Pin or verify the script version before scheduled execution. - Supply removal instructions, such as identifying and deleting the exact crontab entries. - Consider a constrained user-level service with restart limits, logging controls, and network restrictions.

T09 · Insecure Skill Coding Practices

Warning
Location
dx-monitor.py:25
Finding
Predictable shared temporary files permit symlink-based file modification## Vulnerability Details **File Location**: `dx-monitor.py:25, 196-210`; `SKILL.md:84-87` **Vulnerability Type**: Unsafe predictable files in a shared temporary directory **Risk Level**: Medium ### Vulnerable Code ```python STATE_FILE = "/tmp/dx-monitor-state.json" ``` ```python def load_state() -> Dict: """Load previous state.""" try: with open(STATE_FILE) as f: return json.load(f) except: return {'last_spots': [], 'last_check': 0} def save_state(state: Dict): """Save state.""" with open(STATE_FILE, 'w') as f: json.dump(state, f, indent=2) ``` The recommended scheduled command also appends to a predictable shared path: ```cron */5 * * * * cd ~/clawd && python3 skills/ham-radio-dx/dx-monitor.py watch --new-only --callsign YOUR_CALL >> /tmp/dx-alerts.log ``` ### Technical Analysis `/tmp` is normally writable by every local user. Although its sticky bit prevents one user from deleting another user's files, it does not prevent an attacker from creating an absent predictable filename first. Python's ordinary `open(..., 'w')` follows symbolic links and truncates the resolved target. Similarly, the shell follows symbolic links when opening a redirection target with `>>`. Neither operation verifies file ownership, rejects symbolic links, or creates the file within a private directory. Consequently, a local attacker can pre-create `/tmp/dx-monitor-state.json` or `/tmp/dx-alerts.log` as a symbolic link to a file writable by the victim. The next invocation then modifies the linked target. An attacker can also populate the shared state file with attacker-selected JSON to disrupt duplicate filtering. ### Attack Path 1. A local attacker determines that a victim uses this Skill. 2. Before the victim's first execution, the attacker creates a symbolic link at `/tmp/dx-monitor-state.json` pointing to a file writable by the vict ...[truncated 1028 chars]
Remediation
## Remediation Suggestions - Store state beneath a private per-user directory such as `$XDG_STATE_HOME/ham-radio-dx` or `~/.local/state/ham-radio-dx`. - Create the containing directory with permission mode `0700`. - Create state and log files with mode `0600`. - Reject symbolic links by using `os.open()` with `O_NOFOLLOW`, `O_CREAT`, and appropriate exclusivity checks. - Verify that any existing file is a regular file owned by the current user. - Write state to a securely created temporary file in the same private directory, flush it, and atomically replace the destination. - Replace `/tmp/dx-alerts.log` with a private logging location or a controlled logging service. - Never recommend running the monitor as root.

T09 · Insecure Skill Coding Practices

Warning
Location
dx-monitor.py:91
Finding
Unauthenticated network content is printed without terminal-control sanitization## Vulnerability Details **File Location**: `dx-monitor.py:91-129, 282-284, 334` **Vulnerability Type**: Plaintext transport and unsafe rendering of remote content **Risk Level**: Medium ### Vulnerable Code ```python # Request spots self.sock.sendall(f"show/dx {count}\n".encode()) time.sleep(0.5) # Read response data = self._read_available().decode('utf-8', errors='ignore') # Parse spots spots = [] for line in data.split('\n'): spot = self._parse_spot_line(line) if spot: spots.append(spot) ``` ```python spotter = parts[2].rstrip(':') freq = float(parts[3]) dx_call = parts[4] comment = ' '.join(parts[5:-1]) if len(parts) > 5 else '' time_str = parts[-1] if len(parts) > 5 else '' ``` ```python print(f" {band:5} {mode:6} {spot['frequency']:8.1f} {spot['dx_station']:12} - {spot['comment']}") if args.verbose: print(f" Spotted by {spot['spotter']} at {spot['time']}") ``` ```python print(f" 🌍 {spot['dx_station']:12} {spot['band']:5} {spot['frequency']:8.1f} - {spot['comment']}") ``` ### Technical Analysis The client uses a raw TCP socket to connect to DX cluster endpoints. The connection has no transport encryption, certificate validation, or server authentication. The submitted callsign and returned spot data are therefore observable and modifiable by a suitably positioned network attacker. Fields received from the server—including station identifiers, comments, spotter names, and time strings—are interpolated directly into terminal and log output. Parsing with `str.split()` removes ordinary whitespace but does not reliably remove all terminal control characters, including escape characters embedded inside tokens. A malicious cluster server, compromised endpoint, or man-in-the-middle attacker can consequently supply forged records or ANSI terminal sequences. The application does not execute these fields as shell commands, so this is not direct comm ...[truncated 1329 chars]
Remediation
## Remediation Suggestions - Prefer DX cluster endpoints that provide authenticated TLS. - If TLS is available, validate certificates and hostnames using a properly configured SSL context. - Clearly warn users when a callsign is transmitted over unauthenticated plaintext transport. - Strip or escape C0/C1 control characters and ANSI escape sequences from every remotely supplied field before display or logging. - Apply strict length and character allowlists to callsigns, timestamps, and station identifiers. - Encode untrusted values according to the selected output format. - Add maximum response and line-length limits to reduce abuse by malicious endpoints. - Distinguish authenticated and unauthenticated data sources in displayed output.

other

Note
Location
README.md:7
Finding
README references a nonexistent setup script for automatic persistence installation## Vulnerability Details **File Location**: `README.md:7-17` **Vulnerability Type**: Misleading installation documentation **Risk Level**: Low ### Vulnerable Documentation ```bash ## Installation # Run setup with YOUR callsign ./scripts/dx-monitoring-setup.sh YOUR_CALLSIGN # Example: ./scripts/dx-monitoring-setup.sh KN4XYZ ``` ```text This installs: - DX spot monitoring every 5 minutes - Daily digest at 9am - Automatic logging ``` ### Technical Analysis The audited project contains only `README.md`, `SKILL.md`, and `dx-monitor.py`. The referenced `scripts/dx-monitoring-setup.sh` is absent. The documentation therefore directs users to execute a setup component that cannot be reviewed or invoked from the supplied package. This discrepancy is not evidence that a hidden script exists, and no remote download instruction was found. However, it creates ambiguity around how cron persistence is intended to be installed and may encourage users to obtain a similarly named script from an unverified external source. ### Attack Path 1. A user follows the installation instructions and discovers that the referenced script is missing. 2. The user searches for or accepts a replacement script from an unrelated or unverified source. 3. A malicious replacement claims to configure DX monitoring. 4. The user executes it under their account. 5. The replacement can install arbitrary persistence or execute commands with the user's privileges. This path depends on unsafe user action outside the supplied repository; the audited files do not automatically retrieve or execute a replacement. ### Impact Assessment There is no direct exploit in the supplied code. The immediate impact is installation failure and uncertainty regarding intended persistence behavior. If a user executes an unverified substitute, that external script could obtain all privileges available to the invoking account.
Remediation
## Remediation Suggestions - Remove the nonexistent setup-script instructions or include the referenced script in the reviewed package. - If a setup script is added, ensure it displays proposed crontab changes and requests explicit confirmation. - Document a fully manual installation path using only files present in the repository. - Do not direct users to download replacement setup scripts from unspecified sources. - Add uninstall and cron-removal instructions. - Keep README behavior synchronized with the actual package contents through release checks or automated documentation tests.
Vulnerability Patterns
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (8)

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
Most of the code aligns with DX cluster monitoring and daily digest generation: it connects to known DX cluster nodes, requests recent spots, parses them, stores seen spots locally, and prints band activity summaries. However, the declared description says it will 'track active DX expeditions,' while the implementation merely prints a static suggestion to check an external website and performs no expedition fetching, parsing, state tracking, or alerting. Additionally, rare spot monitoring is only loosely implemented via a hardcoded prefix check in the digest path, not as a dedicated expedition/rare-station tracking system. Because one of the stated core functions is not actually implemented, this is a description-behavior mismatch.

YARA rule 'backdoor_persistence': Backdoor persistence with malicious payloads (shell commands, SSH key injection, hidden root users) [malware]

High
Category
YARA Match
Content
��� ZL2ABC       15m     21.074 - New Zealand
```

## DX Cluster Nodes

Available clusters:
- **ea7jxh** - dx.ea7jxh.eu:7373 (Europe)
- **om0rx** - cluster.om0rx.com:7300 (Europe)
- **oh2aq** - oh2aq.kolumbus.fi:7373 (Finland)
- **ab5k** - ab5k.net:7373 (USA)
- **w6rk** - telnet.w6rk.com:7373 (USA West Coast)

## Automated Monitoring

### Real-Time Alerts (Check Every 5 Minutes)

```bash
# Add to crontab
*/5 * * * * cd ~/clawd && python3 skills/ham-radio-dx/dx-monitor.py watch --new-only --callsign YOUR_CALL >> /tmp/dx-alerts.log
```

This checks for new DX spots every 5 minutes and logs them.

### Daily Digest (9am Every Day)

```bash
# Add to crontab
0 9 * * * cd ~/clawd && python3 skills/ham-radio-dx/dx-monitor.py digest >> ~/dx-digest-$(date +\%Y-\%m-\%d).txt
```

### Telegram Notifications

Integrate with Clawdbot message tool:

```bash
# When rare DX appears, send Telegram alert
python3 dx-monitor.py watch --new-only | grep -E "(VP8|ZL|VK|ZS|P5)" && \
  echo "🚨 Rare DX spotted
Confidence
75% confidence
Finding
YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Lp3

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding
Without declared permissions the skill's intent is opaque and cannot be validated.

Session Persistence

Medium
Category
Rogue Agent
Content
### Real-Time Alerts (Check Every 5 Minutes)

```bash
# Add to crontab
*/5 * * * * cd ~/clawd && python3 skills/ham-radio-dx/dx-monitor.py watch --new-only --callsign YOUR_CALL >> /tmp/dx-alerts.log
```
Confidence
85% confidence
Finding
The cron-based setup establishes recurring execution outside the immediate user session, which is a real persistence mechanism. Although presented for legitimate monitoring, persistence increases risk in agent ecosystems because it can continue network activity and file writes after the original interaction, reducing user visibility and control.

Session Persistence

Medium
Category
Rogue Agent
Content
def load_state() -> Dict:
    """Load previous state."""
    try:
        with open(STATE_FILE) as f:
            return json.load(f)
Confidence
87% confidence
Finding
The script persists session-like monitoring state in a fixed world-writable temporary path (/tmp/dx-monitor-state.json) without validating ownership, type, or permissions. On multi-user systems, an attacker can pre-create or replace this file with a symlink or crafted content to influence program behavior, overwrite arbitrary files accessible to the user, or cause misleading spot filtering/state corruption.

Missing User Warnings

Low
Confidence
82% confidence
Finding
The automated monitoring examples instruct users to create cron jobs that append to /tmp and home-directory files without warning that this creates persistent local artifacts. In an agent environment, silent persistence can surprise users, leak operational history, or consume storage over time, especially when logs contain callsigns or monitoring patterns.

Vague Triggers

Low
Confidence
84% confidence
Finding
The "Example Prompts for Clawdbot" section provides generic requests like "What's active on 20 meters?" and "Any rare DX on the air?" without clarifying when the skill should activate versus when it should not. There are no negative examples or narrowing conditions, so the trigger scope remains underspecified.

Vague Triggers

Low
Confidence
89% confidence
Finding
The example prompt "Check the DX cluster for new spots" is a natural-language activation phrase in markdown that is fairly broad and lacks explicit scope constraints or exclusion examples. Because the file presents these as prompts for invoking the skill, this could increase the chance of unintended activation from similar everyday requests.

Static analysis

No suspicious patterns detected.