Back to skill

Security audit

AgentPulse Monitor

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a real monitoring agent, but its installer, credential handling, transport security, and persistence controls are too risky for automatic trust.

Review this carefully before installing, especially on production servers. Require a verified release or package, remove curl-to-bash installation, restore normal TLS validation, protect and rotate API credentials, and provide a clear uninstall path for cron jobs before trusting it.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • 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
Findings (3)

T03 · Remote Payload Retrieval and Execution

Error
Location
SKILL.md:43
Finding
Unverified Remote Script Executed Directly Through Bash<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:43` **Vulnerability Type**: Remote payload retrieval and immediate execution **Risk Level**: High ### Vulnerable Code ```bash curl -fsSL https://agentpulse.io/install.sh | bash -s -- --api-key YOUR_API_KEY --server-id YOUR_SERVER_ID ``` ### Technical Analysis The recommended installation command pipes a remotely hosted, mutable script directly into Bash. The package does not pin a script version, verify a cryptographic checksum, validate a digital signature, or provide an opportunity to inspect the downloaded content before execution. Consequently, the code that users execute can differ from the code reviewed during this audit. Security of the installation process depends entirely on the continuing integrity of the remote domain, DNS, hosting infrastructure, and deployment account. The API key and server identifier are also supplied as command-line arguments to the remote script. Depending on the operating system and process visibility controls, arguments may temporarily be visible to other local users through process-inspection facilities. The manual installation alternative has a related integrity weakness because it downloads a mutable Python file without signature or checksum validation, although it does not pipe that file directly into a shell. ### Attack Path 1. An attacker compromises the `agentpulse.io` hosting environment, deployment credentials, domain, or DNS resolution. 2. The attacker replaces or redirects `install.sh` with a malicious script. 3. A user follows the documented one-line installation procedure. 4. `curl` retrieves the attacker-controlled response and immediately sends it to Bash. 5. The malicious commands execute with the privileges of the installing user. 6. If the command is invoked from a root shell or through an equivalent privileged installation context, the payload obtains root-level execution. ### Impact Assessment Successful exploitation provides arbi ...[truncated 577 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the `curl | bash` installation method. 2. Publish immutable, versioned release artifacts from a verifiable release channel. 3. Publish SHA-256 checksums and preferably sign releases using a maintained signing key. 4. Require users to download the artifact, verify its signature or checksum, inspect it if necessary, and only then execute it. 5. Pin documentation to a specific release version rather than a mutable URL. 6. Avoid passing secrets as command-line arguments. Read the API key from a root-readable configuration file, protected file descriptor, or interactive prompt. 7. Document the exact permissions required for installation and operation, and advise against running the agent as root unless strictly necessary. 8. Apply the same integrity verification to the manual download at `https://agentpulse.io/downloads/agent_client.py`. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
src/agent_client.py:158
Finding
TLS Certificate and Hostname Verification Disabled for Sensitive Telemetry<![CDATA[ ## Vulnerability Details **File Location**: `src/agent_client.py:158-161` **Vulnerability Type**: Improper certificate validation **Risk Level**: Critical ### Vulnerable Code ```python # Allow self-signed certs for dogfood phase ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE ``` This context is then used for the request: ```python with urllib.request.urlopen(req, context=ctx, timeout=30) as resp: return resp.status == 200 ``` ### Technical Analysis The client explicitly disables both certificate-chain validation and hostname verification. Although the URL uses HTTPS, the client will trust any certificate presented by the remote endpoint, including a self-signed certificate generated by an attacker. The report payload contains the API key, server identifier, hostname, service states, load values, memory and disk measurements, and—during full reports—process count, uptime, and listening TCP ports. Because server identity is not authenticated, HTTPS does not provide effective protection against an active man-in-the-middle attack. The API credential is included directly in the JSON body: ```python payload = json.dumps({ "server_id": SERVER_ID, "api_key": API_KEY, "metrics": data, }).encode() ``` An interceptor accepted as the server can therefore capture both credentials and infrastructure telemetry. The attacker may also alter responses or redirect reports to a fraudulent service. ### Attack Path 1. The monitoring agent initiates a report upload to the configured API URL. 2. An attacker gains a privileged network position, controls a proxy, compromises DNS, or otherwise redirects the connection. 3. The attacker presents an arbitrary or self-signed TLS certificate. 4. The client accepts the certificate because certificate validation and hostname verification are disabled. 5. The client sends the API key, server ID, and host telemetry to the attacker-controlled endpoint. 6. The at ...[truncated 912 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the custom insecure TLS settings and use the default verified context: ```python ctx = ssl.create_default_context() ``` 2. Do not set `check_hostname` to `False` or `verify_mode` to `ssl.CERT_NONE`. 3. If a private or development certificate authority is required, configure its CA certificate explicitly: ```python ctx = ssl.create_default_context(cafile="/etc/agentpulse/ca.pem") ``` 4. Separate development and production behavior. Never allow insecure TLS through the production default. 5. Fail closed when certificate or hostname validation fails. 6. Transmit the API credential in an authorization header rather than embedding it in the report body, while retaining verified TLS. 7. Use narrowly scoped, revocable credentials that authorize only report submission for the assigned server. 8. Rotate all credentials that may already have been transmitted using the insecure client. 9. Consider certificate or public-key pinning only if a secure rotation procedure can be maintained. ]]>

T06 · System Persistence

Warning
Location
src/agent_client.py:181
Finding
Persistent Scheduled Execution Installed Through User Crontab<![CDATA[ ## Vulnerability Details **File Location**: `src/agent_client.py:181-199` **Vulnerability Type**: Persistent scheduled task installation **Risk Level**: Medium ### Vulnerable Code ```python def install_cron(): """Install cron entries for scheduled reporting.""" agent_path = os.path.abspath(__file__) entries = [ f"*/5 * * * * {sys.executable} {agent_path} --quick", f"*/30 * * * * {sys.executable} {agent_path} --full", f"0 8 * * * {sys.executable} {agent_path} --full", ] try: result = subprocess.run(["crontab", "-l"], capture_output=True, text=True) existing = result.stdout if result.returncode == 0 else "" lines = [l for l in existing.splitlines() if "agentpulse" not in l.lower() and l.strip()] lines.extend(entries) new_cron = "\n".join(lines) + "\n" proc = subprocess.run(["crontab", "-"], input=new_cron, text=True) ``` ### Technical Analysis The `--install` option modifies the invoking user's crontab and establishes three recurring tasks. These tasks survive the original process and future login sessions, resulting in persistent execution and recurring transmission of server telemetry. Periodic execution is consistent with the declared monitoring functionality and the behavior is documented, so this is not covert persistence. Nevertheless, it creates security exposure because: - No uninstall or rollback operation is provided. - Cron executes the Python file from its current absolute path without verifying its ownership, permissions, integrity, or version. - Replacement of that file can turn the existing schedule into recurring execution of unauthorized code. - The current crontab is rewritten in full rather than using a dedicated, managed service definition. - Any existing nonempty crontab line containing the case-insensitive string `agentpulse` is removed, even if it is unrelated. - The 08:00 daily full report overlaps with the every-30-minute full rep ...[truncated 1812 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require explicit administrator opt-in before installing recurring tasks and display the exact schedule that will be created. 2. Add a supported `--uninstall` option that removes only entries owned by this agent. 3. Mark managed entries using exact begin/end comments and remove only content within those markers. 4. Avoid broad substring filtering such as deleting every crontab line containing `agentpulse`. 5. Install a versioned, integrity-verified agent in a directory that is not writable by unprivileged users. 6. Validate ownership and permissions before creating the schedule. 7. Run the agent under a dedicated least-privileged service account rather than root. 8. Prefer a hardened systemd timer and service with controls such as `NoNewPrivileges`, filesystem restrictions, capability restrictions, and an explicit environment file where supported. 9. Consolidate the schedule to avoid the duplicate full report at 08:00. 10. Document how to disable scheduling, remove credentials, delete collected configuration, and verify that no persistent task remains. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (18)

Tainted flow: 'req' from os.environ.get (line 163, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
ctx.verify_mode = ssl.CERT_NONE

    try:
        with urllib.request.urlopen(req, context=ctx, timeout=30) as resp:
            return resp.status == 200
    except urllib.error.HTTPError as e:
        print(f"API error: {e.code} {e.reason}", file=sys.stderr)
Confidence
99% confidence
Finding
The agent sends sensitive host inventory and credentials over HTTPS with certificate validation explicitly disabled (`check_hostname=False`, `CERT_NONE`). Because the destination URL is environment/config-controlled, an attacker on the network or controlling DNS/proxying can intercept traffic, steal the API key, and receive detailed system telemetry intended for the cloud service.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
The document markets the skill as AI-powered, real-time, and auto-remediating, while the described behavior is periodic reporting, remote cloud analysis, and installation/configuration steps with sensitive host access. This overstatement can mislead operators into trusting the system's capabilities and safety model, causing risky deployment decisions or overbroad access based on inaccurate expectations.

External Script Fetching

High
Category
Supply Chain
Content
### 1. Register Your Server

```bash
curl -X POST https://api.agentpulse.io/v1/servers \
  -H "Content-Type: application/json" \
  -d '{"hostname": "my-server", "plan": "starter"}'
```
Confidence
93% confidence
Finding
The finding spans into the install flow that fetches and executes a remote installer/script, which is a classic external-script-fetching risk. Because the skill is for infrastructure monitoring and encourages host-level installation plus recurring execution, a compromised distribution path could grant persistent code execution across production systems.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill instructs users to perform network operations, download/install software, write files under privileged paths, and schedule recurring execution, but it does not declare any tool scope or permissions. That mismatch reduces transparency and informed consent, making it easier for a user or agent to trigger sensitive actions without clear up-front disclosure.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The skill states that the agent ships server metrics to a cloud API and that the provider stores history and performs analysis, but it does not clearly warn about ongoing external data transmission or the types of operational metadata that may leave the host. In an infrastructure-monitoring context, this can disclose sensitive topology, service, process, and availability information to a third party.

External Transmission

Medium
Category
Data Exfiltration
Content
### 1. Register Your Server

```bash
curl -X POST https://api.agentpulse.io/v1/servers \
  -H "Content-Type: application/json" \
  -d '{"hostname": "my-server", "plan": "starter"}'
```
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
### 1. Register Your Server

```bash
curl -X POST https://api.agentpulse.io/v1/servers \
  -H "Content-Type: application/json" \
  -d '{"hostname": "my-server", "plan": "starter"}'
```
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
Piping a remote script directly into bash executes whatever the server returns at install time with the caller's privileges, eliminating an inspection step and creating a high-risk supply-chain path. In this context the command is part of the primary install flow for infrastructure software, so compromise of the site, CDN, DNS, or TLS trust chain could immediately lead to host takeover.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The manual installation instructions place an executable in /usr/local/bin and write API credentials to /etc/agentpulse.conf without warning about privileged system modification or secret handling. This can expose credentials through weak file permissions, backups, shell history, or multi-user access, while also normalizing root-level changes without informed consent.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
"""Check if a systemd service is active."""
    resolved = SERVICE_ALIASES.get(name, name)
    try:
        result = subprocess.run(
            ["systemctl", "is-active", resolved],
            capture_output=True, text=True, timeout=5
        )
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Context-Inappropriate Capability

Medium
Confidence
79% confidence
Finding
The manifest emphasizes infrastructure monitoring with real-time alerts and baseline learning, which justifies collecting health metrics. However, collecting listening ports via `ss -tlnp` and process counts materially increases system inventory/reconnaissance capability and is not clearly justified by the stated purpose in this manifest text.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
Full reports transmit detailed system and network inventory, including listening ports and process counts, without a clear warning or confirmation at runtime. In this skill context, the danger is amplified because the same data is sent over a TLS channel with verification disabled, increasing the risk of unintended disclosure to an attacker.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
# Listening ports
    ports = set()
    try:
        result = subprocess.run(
            ["ss", "-tlnp"], capture_output=True, text=True, timeout=10
        )
        for line in result.stdout.splitlines()[1:]:
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Description-Behavior Mismatch

Medium
Confidence
90% confidence
Finding
This monitoring agent also installs recurring cron jobs, creating local persistence and modifying system scheduling beyond passive observation. In skill context, that makes the behavior more dangerous because users may expect telemetry collection but not enduring scheduler changes, especially when full reports include detailed host inventory.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The install path modifies the user's crontab immediately, without any confirmation prompt, dry run, or rollback mechanism. This creates persistence and can silently alter host behavior in a way users may not anticipate from a monitoring agent, making it materially riskier in deployment environments.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
f"0 8 * * * {sys.executable} {agent_path} --full",
    ]
    try:
        result = subprocess.run(["crontab", "-l"], capture_output=True, text=True)
        existing = result.stdout if result.returncode == 0 else ""
        lines = [l for l in existing.splitlines() if "agentpulse" not in l.lower() and l.strip()]
        lines.extend(entries)
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
lines = [l for l in existing.splitlines() if "agentpulse" not in l.lower() and l.strip()]
        lines.extend(entries)
        new_cron = "\n".join(lines) + "\n"
        proc = subprocess.run(["crontab", "-"], input=new_cron, text=True)
        if proc.returncode == 0:
            print("Cron entries installed successfully.")
        else:
Confidence
82% confidence
Finding
While the subprocess call itself is not shell-injection prone, it writes a new crontab entry using `sys.executable` and `__file__` without escaping or validating those values. If the agent resides in a path containing spaces or cron metacharacters, the installed cron line can execute unexpectedly or fail, and the function also alters persistence without additional safeguards.

Intent-Code Divergence

Low
Confidence
88% confidence
Finding
The top-level docstring presents the program as an agent that reports system metrics to the cloud API and shows usage including installation, but it does not communicate that installation rewrites the current crontab. This documentation understates a meaningful side effect and gives a narrower impression than the code's actual behavior.

Static analysis

No suspicious patterns detected.