Back to skill

Security audit

VPS Guardian

Security checks for vulnerabilities and agentic risk

Overview

This VPS automation skill is not clearly malicious, but it installs and runs high-impact root-level remediation with weak reviewability and insufficient approval controls.

Review carefully before installing. Do not use the documented sudo curl install path unless the payload is pinned and verified. Start with dry-run only, avoid daemon or cron mode on production hosts, and require explicit approvals, allowlists, backups, and rollback plans before enabling process kills, /tmp cleanup, service restarts, cache drops, or firewall changes.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (4)

T03 · Remote Payload Retrieval and Execution

Error
Location
SKILL.md:27
Finding

Mutable Remote Executable Installed into a Privileged System Path

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
src/guardian.py:88
Finding

Flawed CPU Detection Can Terminate Critical Processes as Root

Content
View full analysis
0 else 0 procs.append({ "pid": pid, "comm": comm, "cmdline": cmdline or comm, "state": state, "cpu_pct": round(cpu_pct, 1), "rss": rss, "utime": utime, "stime": stime, }) ``` ```python for p in procs: if kill_count >= MAX_KILLS_PER_CYCLE: break if p["pid"] in PROTECTED_PIDS or p["comm"] in PROTECTED_COMM: continue if "guardian" in p["cmdline"].lower(): continue # Zombie check if p["state"] == "Z" and cfg["zombie_kill"]: msg = f"ZOMBIE pid={p['pid']} comm={p['comm']} → reaping parent" log(msg) if not dry_run: # Zombies can't be killed directly; signal parent tr ...[truncated 3547 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
src/guardian.py:198
Finding

Root-Level Cleanup Deletes Unrelated Files from Shared Temporary Storage

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
src/guardian.py:345
Finding

Documented Firewall Approval Gate Is Not Implemented

Content
View full analysis
= cfg["max_ssh_failures"]: msg = f"SECURITY {count} SSH failures from {ip}" if cfg["auto_block"] and not dry_run: log(f"{msg} → blocking via iptables") subprocess.run( ["iptables", "-A", "INPUT", "-s", ip, "-j", "DROP"], capture_output=True, timeout=10 ) remediated = True else: log(f"{msg} → BLOCK RECOMMENDED (auto_block=false)") ``` The documented safety claims conflict with this implementation: ```text Never auto-blocks — always requires approval (prevents lockout) Approval gate: Security actions always require confirmation ``` ### Technical Analysis No interactive, authenticated, or external approval mechanism exists. If `auto_block` is enabled, the code immediately appends an `iptables` DROP rule without confirmation. Failure counts are calculated by scanning all matching entries in the available `auth.log`, rather than a bounded recent time window. Historical login failures can therefore trigger blocking long after the relevant activity occurred. Repeated scans can append duplicate rules because the code does not check whether an equivalent rule already exists. The implementation also provides no automatic expiry, rollback, lockout protection, or validation that a source address belongs to an administrator or trusted management network. While the IP value is safely passed as a subprocess argument rather than through a shell, the authorization and lifecycle controls around the firewall change are inadequate. ### Attack Path 1. An administrator enables `auto_block`, relying on t ...[truncated 977 chars]
Remediation
View remediation
Vulnerability Patterns
  • 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
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (26)

Missing User Warnings

High
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill prominently advertises autonomous destructive actions—killing processes, freeing disk, restarting services, and hardening security—without an upfront warning about service interruption, data loss, or lockout risk. In a VPS-management context, these actions can directly affect availability and system integrity if triggered incorrectly or on incomplete telemetry.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The docstring says approval is required for blocking, but the code can automatically block IPs when auto_block is enabled in configuration. This mismatch is dangerous because it undermines operator expectations and can cause privileged, security-sensitive actions to occur without the human review the documentation promises.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill describes capabilities that clearly imply shell execution and filesystem modification, but it declares no explicit tool scope or permission boundaries. For an autonomous remediation skill that can kill processes, restart services, and modify security settings, this omission is dangerous because an agent may be granted broader-than-necessary powers without user visibility or enforcement.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The skill is framed with broad activation language such as autonomous monitoring, fixing, and hardening, without clear trigger constraints or bounded operating conditions. In an agent ecosystem, vague scope increases the chance the skill is invoked in inappropriate contexts and performs destructive actions on production systems without sufficiently specific user intent.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · SKILL.md (reported line 29)May include surrounding context.

bash
# Download
sudo curl -o /usr/local/bin/vps-guardian https://raw.githubusercontent.com/vps-guardian/guardian/main/src/guardian.py
sudo chmod +x /usr/local/bin/vps-guardian

# Configure (optional — defaults are sensible)

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · SKILL.md (reported line 30)May include surrounding context.

bash
# Download
sudo curl -o /usr/local/bin/vps-guardian https://raw.githubusercontent.com/vps-guardian/guardian/main/src/guardian.py
sudo chmod +x /usr/local/bin/vps-guardian

# Configure (optional — defaults are sensible)

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · SKILL.md (reported line 33)May include surrounding context.

bash
# Download
sudo curl -o /usr/local/bin/vps-guardian https://raw.githubusercontent.com/vps-guardian/guardian/main/src/guardian.py
sudo chmod +x /usr/local/bin/vps-guardian

# Configure (optional — defaults are sensible)

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
70% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

Scanner excerpt · SKILL.md (reported line 84)May include surrounding context.

md
### 4. Security Hardening
- Detects unexpected listening ports (diffs against baseline)
- Identifies brute-force SSH attempts (fail2ban integration)
- Flags world-writable files in /etc, /root
- Checks for suspicious processes (crypto miners, reverse shells)
- **Action**: Blocks IPs via iptables, chmods files, kills suspicious processes
- Never auto-blocks — always requires approval (prevents lockout)

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The documentation contradicts itself about whether IP blocking is automatic or approval-gated, which creates ambiguity in a security-sensitive autonomous tool. Operators or downstream agents may assume blocking is safe to perform automatically and unintentionally lock out legitimate users or apply firewall changes without consent.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The example logs show an IP being blocked automatically, while the safety section says security actions always require confirmation. This inconsistency can cause implementers or autonomous agents to perform destructive network controls despite policy expectations, undermining trust and safety guarantees.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · SKILL.md (reported line 165)May include surrounding context.

md
- Linux (systemd-based)
- Python 3.8+
- Root or sudo access
- No external dependencies (stdlib only)

## Differences from Monitoring Tools

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The package description explicitly advertises broad autonomous intervention capabilities such as killing processes, freeing disk, restarting services, and hardening security, but it provides no activation boundaries, approval gates, or scope limitations. In a VPS-management skill, this is dangerous because downstream users or agents may interpret the description as authorization for high-impact system changes without explicit user confirmation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The phrase 'Not alerts. Action.' and the listed behaviors indicate the skill is intended to autonomously perform destructive or disruptive remediation rather than merely recommend or request approval. In the context of production VPS administration, such language materially increases risk of accidental service outages, data loss, termination of legitimate workloads, or unsafe security reconfiguration if the skill is invoked by an agent without strong human-in-the-loop controls.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The tool can automatically SIGTERM and then SIGKILL processes based on a flawed CPU heuristic that uses lifetime-average CPU, not current runaway behavior. In an autonomous privileged agent, this is dangerous because it can kill legitimate long-running services or business-critical jobs without confirmation, causing outages or corruption.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · src/guardian.py (reported line 192)May include surrounding context.

python
if age_days > cfg["rotate_logs_days"]:
                size = os.path.getsize(log_file)
                if not dry_run:
                    subprocess.run(["gzip", "-f", log_file], timeout=30, capture_output=True)
                freed += size
        except (OSError, subprocess.TimeoutExpired):
            pass

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The agent deletes files from /tmp automatically based only on age, with no ownership checks, path policy, or explicit user warning beyond logs. In a self-healing VPS tool, this can destroy legitimate temporary application data and cause service outages or data loss, especially because /tmp is shared by many processes and applications.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · src/guardian.py (reported line 212)May include surrounding context.

python
# Truncate journal if too large
    if cfg["journal_max_size_mb"]:
        try:
            result = subprocess.run(
                ["journalctl", "--disk-usage"],
                capture_output=True, text=True, timeout=10
            )

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · src/guardian.py (reported line 226)May include surrounding context.

python
size_mb *= 1024
                        if size_mb > cfg["journal_max_size_mb"]:
                            if not dry_run:
                                subprocess.run(
                                    ["journalctl", "--vacuum-size=f{cfg['journal_max_size_mb']}M"],
                                    timeout=30, capture_output=True
                                )

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · src/guardian.py (reported line 241)May include surrounding context.

python
if cfg["apt_cache_clean"]:
        try:
            if not dry_run:
                result = subprocess.run(
                    ["apt-get", "clean"], timeout=30, capture_output=True
                )
                if result.returncode == 0:

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

Automatic service restarts are disruptive actions that can interrupt active sessions, reset stateful services, or worsen failures when root cause is unknown. In the context of this skill, the risk is elevated because restart targets can be influenced by configuration and are attempted repeatedly without an explicit user-approval step.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · src/guardian.py (reported line 271)May include surrounding context.

python
for svc in critical_services:
        try:
            result = subprocess.run(
                ["systemctl", "is-active", svc],
                capture_output=True, text=True, timeout=5
            )

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · src/guardian.py (reported line 280)May include surrounding context.

python
log(f"SERVICE {svc}: {status} → restarting")
                if not dry_run:
                    for attempt in range(3):
                        subprocess.run(
                            ["systemctl", "restart", svc],
                            capture_output=True, timeout=30
                        )

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · src/guardian.py (reported line 285)May include surrounding context.

python
capture_output=True, timeout=30
                        )
                        time.sleep(5 * (2 ** attempt))  # exponential backoff
                        check = subprocess.run(
                            ["systemctl", "is-active", svc],
                            capture_output=True, text=True, timeout=5
                        )

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

Writing 3 to /proc/sys/vm/drop_caches changes kernel behavior and can significantly degrade performance or destabilize workloads under memory pressure, while providing limited benefit if used indiscriminately. As an automatic remediation in a privileged daemon, this is dangerous because it performs a system-wide, impactful action without operator acknowledgment or context-aware safeguards.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill's scope expands from health monitoring into active network access control by appending iptables DROP rules. In an autonomous VPS agent, this makes the behavior more dangerous because a monitoring tool is expected to observe and remediate host health, not silently alter perimeter policy, which can create self-inflicted denial of service or unintended blocking of valid clients.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.