Back to skill

Security audit

Pi Admin

Security checks for vulnerabilities and agentic risk

Overview

This Raspberry Pi admin skill is mostly purpose-aligned, but it can reboot the host, kill and restart services, and persistently change system settings with several misleading or under-scoped safety controls.

Install only on a Raspberry Pi you administer and treat it as a privileged maintenance tool, not just a monitor. Review and preferably fix the confirmation behavior, dry-run side effects, hardcoded gateway path and addresses, port mismatch, and optimization undo logic before allowing agents or automation to invoke maintenance commands.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (4)

T09 · Insecure Skill Coding Practices

Warning
Location
update.sh:32
Finding

Update Dry-Run Performs Privileged Network and Filesystem Mutations

Content
View full analysis

Vulnerability Details

File Location: update.sh:32-63
Vulnerability Type: Dry-run safety contract violation
Risk Level: Medium

Vulnerable Code

bash
else
  # In dry-run mode, we need sudo for read operations
  SUDO="sudo"
fi

# Update package lists
echo "Updating package lists..."
$SUDO apt update

# Show upgradable packages
echo ""
echo "Upgradable packages:"
echo "--------------------"
$SUDO apt list --upgradable 2>/dev/null | grep -v "^Listing" | head -20

# Count packages
COUNT=$($SUDO apt list --upgradable 2>/dev/null | grep -v "^Listing" | wc -l)

if [ "$COUNT" -eq 0 ]; then
  echo ""
  echo "✅ System is up to date!"
  exit 0
fi

echo ""
echo "Found $COUNT upgradable package(s)"
echo ""

# Exit early in dry run mode
if [ "$DRY_RUN" = true ]; then
  echo "🔍 Dry run complete. These packages would be updated."
  echo "   Run without --dry-run to apply updates."
  exit 0
fi

Technical Analysis

The script advertises dry-run mode as making no changes, but assigns SUDO="sudo" in that mode and executes sudo apt update before reaching the dry-run exit. apt update is not a read-only operation: it contacts configured package repositories and modifies package-index state under /var/lib/apt/lists and related APT-managed paths.

This violates the documented dry-run safety contract and unnecessarily requests elevated privileges for a preview operation. It can also trigger repository authentication, proxy access, metered network traffic, or interaction with an untrusted repository configured on the host.

Attack Path

  1. A user or automation system invokes ./skill.sh update --dry-run, expecting a side-effect-free preview.
  2. The wrapper forwards --dry-run to update.sh.
  3. The script assigns sudo to SUDO.
  4. sudo apt update contacts every configured APT repository.
  5. APT downloads metadata and changes privileged local package-inde ...[truncated 506 chars]
Remediation
View remediation

Remediation Suggestions

  • Do not run apt update in dry-run mode.
  • Use existing package indexes for the preview, or introduce a separately named and explicitly confirmed --refresh option.
  • Do not assign sudo for operations that only read publicly accessible APT state.
  • Clearly distinguish between a side-effect-free preview and a repository refresh.
  • Enable fail-safe shell behavior such as set -euo pipefail and check command exit statuses before reporting success.
  • Add a regression test that records relevant filesystem state and network calls to verify that --dry-run performs no writes or downloads.

T09 · Insecure Skill Coding Practices

Warning
Location
optimize.sh:100
Finding

Optimization Undo Overwrites Persistent System State Without Restoring the Original Configuration

Content
View full analysis

Vulnerability Details

File Location: optimize.sh:100-125
Vulnerability Type: Unsafe persistent service and kernel configuration restoration
Risk Level: Medium

Vulnerable Code

bash
# Undo mode
if [ "$UNDO" = true ]; then
  echo "Reverting optimizations..."
  echo ""

  if [ "$(systemctl is-enabled bluetooth.service)" = "disabled" ]; then
    echo "Enabling Bluetooth..."
    $SUDO systemctl enable bluetooth.service
    echo "✅ Bluetooth enabled"
  fi

  if [ "$(systemctl is-enabled ModemManager.service)" = "disabled" ]; then
    echo "Enabling ModemManager..."
    $SUDO systemctl enable ModemManager.service
    echo "✅ ModemManager enabled"
  fi

  if [ "$(systemctl is-enabled avahi-daemon.service)" = "disabled" ]; then
    echo "Enabling Avahi..."
    $SUDO systemctl enable avahi-daemon.service
    echo "✅ Avahi enabled"
  fi

  echo "Restoring swappiness to 60..."
  $SUDO sysctl vm.swappiness=60
  echo "vm.swappiness=60" | $SUDO tee /etc/sysctl.d/99-swappiness.conf > /dev/null
  echo "✅ Swappiness restored to 60"

Related persistent optimization operations occur at optimize.sh:137-173:

bash
$SUDO systemctl disable bluetooth.service
$SUDO systemctl disable ModemManager.service
$SUDO systemctl disable avahi-daemon.service
$SUDO sysctl vm.swappiness=10
echo "vm.swappiness=10" | $SUDO tee /etc/sysctl.d/99-swappiness.conf > /dev/null

Technical Analysis

The optimization feature legitimately requires persistent configuration changes because its declared purpose includes disabling services and setting swappiness across reboots. These operations are therefore not evidence of a covert backdoor. However, the implementation does not record the original service enablement states or original swappiness configuration.

Consequently, --undo does not actually restore prior state. It enables every target service that is currently disabled, even if ...[truncated 1543 chars]

Remediation
View remediation

Remediation Suggestions

  • Before applying optimizations, record each service’s exact original state, including enabled, disabled, masked, static, and absent states.
  • Record the effective swappiness value and whether the Skill-created sysctl file existed beforehand.
  • Store restoration data in a root-owned file with restrictive permissions and validate its format before use.
  • During undo, restore only settings that a recorded optimization run actually changed.
  • Remove the Skill-created sysctl file when appropriate instead of replacing unknown prior policy with a hardcoded value.
  • Never unmask or enable a service that was already disabled or masked before optimization.
  • Display the exact persistent changes and require affirmative confirmation before both apply and undo operations.
  • Check every systemctl, sysctl, and tee exit status before claiming success.

T09 · Insecure Skill Coding Practices

Warning
Location
restart-gateway.sh:27
Finding

Destructive Reboot and Gateway Termination Operations Lack Affirmative Confirmation

Content
View full analysis

Vulnerability Details

File Locations: restart-gateway.sh:27-49; reboot.sh:27-41; documentation at SKILL.md:154
Vulnerability Type: Unsafe destructive process and availability management
Risk Level: Medium

Vulnerable Code

restart-gateway.sh:27-49:

bash
# Stop running gateway processes
echo "Stopping any running gateway processes..."
pkill -f "clawdis gateway" 2>/dev/null
sleep 2

# Check if processes are still running
REMAINING=$(pgrep -f "clawdis gateway" | wc -l)
if [ "$REMAINING" -gt 0 ]; then
  echo "Force stopping remaining processes..."
  pkill -9 -f "clawdis gateway" 2>/dev/null
  sleep 1
fi

echo "✅ Gateway processes stopped"
echo ""

# Start new gateway
echo "Starting Gateway on port 18789..."
cd /home/srose/clawdis

# Start in background
pnpm clawdis gateway --port 18789 > /dev/null 2>&1 &

reboot.sh:27-41:

bash
echo "⚠️  This will reboot the system!"
echo ""
echo "To cancel, press Ctrl+C"
echo ""

# Countdown
for i in {10..1}; do
  echo -ne "\rRebooting in $i seconds... "
  sleep 1
done

echo ""
echo ""
echo "🔄 Rebooting now..."
$SUDO reboot

The documentation states:

text
All maintenance commands require sudo and ask for confirmation before making changes.

Technical Analysis

Neither operation obtains affirmative user consent. The reboot command merely provides a countdown, while the gateway restart immediately sends termination signals.

The gateway script uses pkill -f "clawdis gateway", which matches the full command line rather than a verified process identity. This can terminate unrelated processes whose arguments happen to contain the same string. It escalates to SIGKILL, preventing matched processes from performing graceful shutdown or cleanup.

The script then changes into a hardcoded directory without checking whether cd succeeded. Because shell execution continues a ...[truncated 1221 chars]

Remediation
View remediation

Remediation Suggestions

  • Require an explicit yes/no confirmation before terminating processes or rebooting.
  • Provide a separately documented --yes option for controlled, noninteractive automation.
  • Manage the gateway through a dedicated systemd unit or another process supervisor.
  • If a service manager is unavailable, use a protected PID file and verify the PID’s executable, owner, and start time before signaling it.
  • Avoid pkill -f; never use broad SIGKILL matching as the default shutdown mechanism.
  • Attempt graceful termination, wait for the exact process, and use SIGKILL only for that verified PID after a defined timeout.
  • Change directories using cd /home/srose/clawdis || exit 1.
  • Replace hardcoded user-specific paths and addresses with validated configuration.
  • Check restart and reboot command results before reporting success.
  • Correct the documentation so its confirmation guarantees match actual behavior.

other

Note
Location
network.sh:9
Finding

Combined Inventory Commands Expose Broad Host and Network Reconnaissance Data

Content
View full analysis

Vulnerability Details

File Locations: network.sh:9-48, tailscale.sh:17-48, services.sh:21-45, storage.sh:33-41, dispatched collectively by skill.sh:50-70
Vulnerability Type: Excessive system reconnaissance and information exposure
Risk Level: Low

Representative Code

network.sh:9-48:

bash
echo "Hostname: $(hostname)"
echo "FQDN: $(hostname -f 2>/dev/null || echo "N/A")"

hostname -I 2>/dev/null | tr ' ' '\n' | while read ip; do
  [ -n "$ip" ] && echo "  - $ip"
done

for iface in /sys/class/net/*; do
  name=$(basename "$iface")
  if [ -f "$iface/operstate" ]; then
    state=$(cat "$iface/operstate")
    mac=$(cat "$iface/address" 2>/dev/null)
    ip=$(ip -4 addr show "$name" 2>/dev/null | grep -oP 'inet \K[0-9.]+' | head -1)
    echo "  $name: $state"
    [ -n "$ip" ] && echo "    IP: $ip"
    [ -n "$mac" ] && echo "    MAC: $mac"
  fi
done

cat /etc/resolv.conf 2>/dev/null | grep nameserver | while read line; do
  echo "  $line"
done

ip route | grep default | awk '{print "  via " $3 " dev " $5}'

Additional inventory operations include:

bash
tailscale status
tailscale ip
systemctl list-units --type=service --state=running
docker ps
ss -tuln
mount
du -sh /home/*/

Technical Analysis

The information-gathering behavior is declared in SKILL.md and no code was found that transmits the collected data externally. It is therefore not covert exfiltration. Nevertheless, the all command combines hostnames, IP and MAC addresses, DNS and routing configuration, Tailscale addresses and peers, active services, Docker containers, listening ports, mounts, and user-home storage information into one output stream.

This collection exceeds minimum disclosure for a basic system health check. If agent output, command logs, support transcripts, or API responses are visible to an untrusted party, the resulting dataset provides ...[truncated 1045 chars]

Remediation
View remediation

Remediation Suggestions

  • Make the default overview minimal and redact MAC addresses, VPN peer details, DNS servers, routes, and listening addresses.
  • Require explicit subcommands or flags for sensitive inventory such as Tailscale peers, Docker workloads, listeners, and home-directory usage.
  • Avoid including /home/* information unless storage analysis is specifically requested.
  • Restrict Skill invocation and transcript access to trusted administrators.
  • Avoid persisting command output, or apply retention controls and output redaction before logging.
  • Document the sensitivity of skill.sh all and require affirmative confirmation before producing the complete inventory.
Vulnerability Patterns
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (6)

Tp4

High
Category
MCP Tool Poisoning
Confidence
88% confidence
Finding

The skill is presented as general Raspberry Pi administration, but the documented behavior goes beyond routine monitoring into service-specific process killing/restarting, launching a user-scoped application from a hardcoded path, exposing service endpoints, and applying persistent system configuration changes. This mismatch is dangerous because users or orchestrators may grant broad trust based on the benign description while the skill can materially alter host state and availability.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script's dry-run output, startup messages, and connection details inconsistently reference ports 18789 and 18790, while the actual command starts the gateway on 18789. In a system administration skill, this can cause operators to connect to or firewall the wrong port, mis-verify service health, and make unsafe maintenance decisions during restart or incident response.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This wrapper exposes maintenance actions including update, clean, reboot, and restart-gateway directly from a single entrypoint without any confirmation prompt, privilege check, or contextual warning. In an agent-driven environment, this increases the chance of accidental or unauthorized disruptive execution, especially for commands that can reboot the device or interrupt connectivity.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Enabling bluetooth.service makes the service persist across reboots, which qualifies as a persistence-related system change. In this script it is presented as explicit undo functionality, so it is not malicious, but it still changes boot-time behavior and could unexpectedly expose Bluetooth attack surface if run on systems where it was intentionally disabled for security.

Content

Scanner excerpt · optimize.sh (reported line 106)May include surrounding context.

sh
if [ "$(systemctl is-enabled bluetooth.service)" = "disabled" ]; then
    echo "Enabling Bluetooth..."
    $SUDO systemctl enable bluetooth.service
    echo "✅ Bluetooth enabled"
  fi

Session Persistence

Medium
Category
Rogue Agent
Confidence
76% confidence
Finding

systemctl enable ModemManager.service persists the service across reboots and therefore changes system startup behavior. While framed as rollback, it may re-enable modem-related functionality that an administrator had intentionally disabled outside this script, increasing connectivity and attack surface unexpectedly.

Content

Scanner excerpt · optimize.sh (reported line 112)May include surrounding context.

sh
if [ "$(systemctl is-enabled ModemManager.service)" = "disabled" ]; then
    echo "Enabling ModemManager..."
    $SUDO systemctl enable ModemManager.service
    echo "✅ ModemManager enabled"
  fi

Session Persistence

Medium
Category
Rogue Agent
Confidence
78% confidence
Finding

Enabling avahi-daemon.service persists multicast DNS/service discovery at boot, which broadens network visibility and attack surface. In context this is intended as undo logic, but it is still risky because the script does not track whether Avahi was disabled by the script or by prior hardening decisions.

Content

Scanner excerpt · optimize.sh (reported line 118)May include surrounding context.

sh
if [ "$(systemctl is-enabled avahi-daemon.service)" = "disabled" ]; then
    echo "Enabling Avahi..."
    $SUDO systemctl enable avahi-daemon.service
    echo "✅ Avahi enabled"
  fi

Static analysis

No suspicious patterns detected.