Back to skill

Security audit

Autotask Mcp

Security checks for vulnerabilities and agentic risk

Overview

The skill is a disclosed Autotask MCP Docker integration, but it can run a mutable upstream container with sensitive Autotask credentials and optionally keep updating it automatically.

Review this before installing if your Autotask account has broad permissions. Prefer manual updates, pin and verify the Docker image digest before running it with real credentials, use a least-privilege Autotask API account, and be cautious about enabling the weekly auto-update timer.

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

T03 · Remote Payload Retrieval and Execution

Error
Location
scripts/mcp_update.sh:23
Finding
Scheduled updater retrieves and executes a mutable remote container image<![CDATA[ ## Vulnerability Details **File Location**: `docker-compose.yml:3`; `scripts/mcp_update.sh:8, 23-53`; `scripts/cron_install.sh:82-103` **Vulnerability Type**: Mutable remote payload retrieval and automatic execution **Risk Level**: High ### Vulnerable Code ```yaml # docker-compose.yml:1-6 services: autotask-mcp: image: ghcr.io/asachs01/autotask-mcp:latest container_name: autotask-mcp env_file: - .env ``` ```bash # scripts/mcp_update.sh:8 IMAGE="ghcr.io/asachs01/autotask-mcp:latest" ``` ```bash # scripts/mcp_update.sh:23-53 docker compose pull 2>&1 | tee -a "$LOGFILE" # Capture new image digest after pull NEW_DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' "$IMAGE" 2>/dev/null || echo "unknown") log "Pulled digest: ${NEW_DIGEST}" # --- Supply chain verification --- # If a pinned digest file exists, verify the pulled image matches it. # Users can pin a known-good digest by running: # ./scripts/mcp_pin_digest.sh if [[ -f "$DIGEST_FILE" ]]; then PINNED=$(< "$DIGEST_FILE") # Extract just the sha256:... portion from the full repo@sha256:... string PULLED_SHA="${NEW_DIGEST##*@}" if [[ "$PULLED_SHA" != "$PINNED" ]]; then log "WARNING: Pulled image digest does NOT match pinned digest!" log " Pinned : ${PINNED}" log " Pulled : ${PULLED_SHA}" log "Refusing to restart. Review the new image and update the pin with:" log " ./scripts/mcp_pin_digest.sh" exit 1 fi log "Digest matches pin: ${PINNED}" fi if [[ "$OLD_DIGEST" != "$NEW_DIGEST" ]]; then log "New image detected." log "Recreating container with updated image..." docker compose up -d 2>&1 | tee -a "$LOGFILE" log "Update complete." else log "Already on latest image. No restart needed." fi ``` ```ini # Generated by scripts/cron_install.sh:80-88 [Unit] Description=Autotask MCP Docker image update [Service] Type=oneshot ExecStart=${SCRIPT_PATH} WorkingDirectory=${SKILL_DIR} ``` ### Technical Analysis The Compose configu ...[truncated 2997 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace the mutable Compose reference with an immutable reviewed digest: ```yaml image: ghcr.io/asachs01/autotask-mcp@sha256:<reviewed-digest> ``` 2. Make verification fail closed. The updater should refuse to pull or start an update when `.pinned-digest` is absent, malformed, or cannot be read. 3. Validate pinned values against a strict format such as `^sha256:[0-9a-f]{64}$`. 4. Do not update the pin automatically from the current `latest` image. Require a separate review and approval workflow before changing the trusted digest. 5. Prefer signature and provenance verification, such as Sigstore/Cosign verification against an explicitly trusted identity, in addition to digest pinning. 6. Separate retrieval from deployment: pull and inspect a candidate image first, then require explicit approval before replacing the running container. 7. If unattended updates remain supported, restrict them to signed release tags and document that enabling the timer authorizes recurring retrieval and execution of upstream code. 8. Use narrowly scoped Autotask credentials with only the permissions needed for the intended MCP operations, and rotate them immediately if an untrusted image may have run. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/cron_uninstall.sh:34
Finding
Legacy scheduler cleanup can delete unrelated crontab entries<![CDATA[ ## Vulnerability Details **File Location**: `scripts/cron_uninstall.sh:34-36` **Vulnerability Type**: Overly broad crontab modification **Risk Level**: Low ### Vulnerable Code ```bash # Also clean up any legacy crontab entries from previous versions if crontab -l 2>/dev/null | grep -q "autotask-mcp"; then (crontab -l 2>/dev/null | grep -v "autotask-mcp" || true) | crontab - echo "Legacy crontab entries removed." fi ``` ### Technical Analysis The uninstaller removes every line in the current user's crontab that contains the substring `autotask-mcp`. It does not verify that a matching line was installed by a previous version of this Skill, nor does it require an exact command, schedule, or ownership marker. Consequently, unrelated user-managed cron jobs can be removed if their command, path, comment, or arguments happen to contain the same substring. The replacement is written directly back through `crontab -`, with no backup or confirmation showing the lines that will be deleted. This operation is limited to the invoking user's crontab and does not modify system-wide or other users' crontabs. It therefore does not constitute privilege escalation, but it violates least-destructive uninstall behavior. ### Attack Path 1. The current user has an unrelated cron entry whose text contains `autotask-mcp`. 2. The user runs the documented `scripts/cron_uninstall.sh` command. 3. The script detects at least one matching line. 4. `grep -v "autotask-mcp"` removes every matching line from the crontab stream. 5. The filtered crontab is installed without displaying the removed entries or requesting confirmation. 6. The unrelated scheduled job no longer executes. ### Impact Assessment The script can delete scheduled tasks owned by the current user. This could interrupt backups, monitoring, maintenance, or other automation if an affected entry contains the matching text. It cannot directly modify another user's crontab or a system-wide scheduler unless it ...[truncated 197 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Give legacy entries a unique, versioned ownership marker, for example: ```text # BEGIN autotask-mcp managed entry v1 ... # END autotask-mcp managed entry v1 ``` 2. Remove only an exact block or exact expected command and schedule rather than every line containing a substring. 3. Capture the current crontab once and create a timestamped backup before modifying it. 4. Display the exact entries selected for removal and request confirmation unless the caller supplies an explicit noninteractive option. 5. If the precise historical entry format is unknown, do not delete it automatically. Report the candidate lines and provide manual cleanup instructions. 6. Add tests showing that similarly named but unrelated entries are preserved while the exact legacy managed entry is removed. ]]>
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
  • Rogue AgentSelf-Modification, Session Persistence
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
Findings (47)

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

High
Category
YARA Match
Content
, noexec, nosuid
- **Resource limits** — Memory capped at 512 MB, CPU capped at 1 core, max 64 PIDs
- **Log rotation** — Container logs limited to 3 files of 10 MB each

### Supply Chain Verification

- **Digest pinning** — Pin a known-good image digest with `scripts/mcp_pin_digest.sh`
- **Update verification** — `mcp_update.sh` refuses to restart if pulled digest doesn't match pin
- **No crontab modification** — Scheduled updates use macOS LaunchAgent or Linux systemd user timers

## Project Structure

```
autotask-mcp/
├── SKILL.md              # Skill definition for MCP clients
├── README.md             # This file
├── docker-compose.yml    # Service configuration
├── .env.example.txt      # Environment variable template
├── .gitignore            # Excludes .env, .pinned-digest, and logs/
├── .pinned-digest        # Pinned image digest (created by mcp_pin_digest.sh)
├── _meta.json            # Skill metadata
├── logs/
Confidence
75% confidence
Finding
YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The skill is described as an Autotask MCP integration, but it also documents installation and removal of host-level scheduled update jobs. That expands behavior beyond simple API interaction into local persistence/configuration management, which can surprise operators and increase the blast radius if the skill or its upstream image is compromised.

Credential Access

High
Category
Privilege Escalation
Content
image: ghcr.io/asachs01/autotask-mcp:latest
    container_name: autotask-mcp
    env_file:
      - .env
    environment:
      # Run the MCP server in HTTP mode inside Docker
      MCP_TRANSPORT: http
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
image: ghcr.io/asachs01/autotask-mcp:latest
    container_name: autotask-mcp
    env_file:
      - .env
    environment:
      # Run the MCP server in HTTP mode inside Docker
      MCP_TRANSPORT: http
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
image: ghcr.io/asachs01/autotask-mcp:latest
    container_name: autotask-mcp
    env_file:
      - .env
    environment:
      # Run the MCP server in HTTP mode inside Docker
      MCP_TRANSPORT: http
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
image: ghcr.io/asachs01/autotask-mcp:latest
    container_name: autotask-mcp
    env_file:
      - .env
    environment:
      # Run the MCP server in HTTP mode inside Docker
      MCP_TRANSPORT: http
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
image: ghcr.io/asachs01/autotask-mcp:latest
    container_name: autotask-mcp
    env_file:
      - .env
    environment:
      # Run the MCP server in HTTP mode inside Docker
      MCP_TRANSPORT: http
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
image: ghcr.io/asachs01/autotask-mcp:latest
    container_name: autotask-mcp
    env_file:
      - .env
    environment:
      # Run the MCP server in HTTP mode inside Docker
      MCP_TRANSPORT: http
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
TIMER_DIR="$HOME/.config/systemd/user"
  if [[ -f "${TIMER_DIR}/autotask-mcp-update.timer" ]]; then
    systemctl --user disable --now autotask-mcp-update.timer 2>/dev/null || true
    rm -f "${TIMER_DIR}/autotask-mcp-update.timer"
    rm -f "${TIMER_DIR}/autotask-mcp-update.service"
    systemctl --user daemon-reload
    echo "Systemd user timer removed."
Confidence
95% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
if [[ -f "${TIMER_DIR}/autotask-mcp-update.timer" ]]; then
    systemctl --user disable --now autotask-mcp-update.timer 2>/dev/null || true
    rm -f "${TIMER_DIR}/autotask-mcp-update.timer"
    rm -f "${TIMER_DIR}/autotask-mcp-update.service"
    systemctl --user daemon-reload
    echo "Systemd user timer removed."
    removed=true
Confidence
95% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Credential Access

High
Category
Privilege Escalation
Content
# --- Gitignore checks ---
echo "[.gitignore]"
check ".env is gitignored"            grep -q '.env' .gitignore
check ".pinned-digest is gitignored"  grep -q '.pinned-digest' .gitignore
check "logs/ is gitignored"           grep -q 'logs/' .gitignore
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
```bash
   cp .env.example.txt .env
   chmod 600 .env
   ```

   Then **manually** open `.env` in your preferred text editor and fill in your credentials.
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
```bash
   cp .env.example.txt .env
   chmod 600 .env
   ```

   Then **manually** open `.env` in your preferred text editor and fill in your credentials.
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
```bash
   cp .env.example.txt .env
   chmod 600 .env
   ```

   Then **manually** open `.env` in your preferred text editor and fill in your credentials.
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
```bash
   cp .env.example.txt .env
   chmod 600 .env
   ```

   Then **manually** open `.env` in your preferred text editor and fill in your credentials.
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
### Credential Protection

- **File permissions** — `.env` is created with `chmod 600` (owner-only read/write)
- **Git exclusion** — `.env` is gitignored to prevent accidental commits
- **No duplication** — Agents are prohibited from copying or moving the `.env` file
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
The skill states that agents must execute only a tightly restricted command list, but later instructs use of additional scheduling scripts not included in that allowlist. Contradictory execution boundaries weaken guardrails and can cause an agent or user to run broader host-modifying commands than intended.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
Installing LaunchAgent or systemd user timers introduces host-level persistence unrelated to the narrow task of interacting with Autotask via a local MCP endpoint. Even if intended for convenience, persistence mechanisms create ongoing execution paths that could be abused by a compromised image, script, or future update.

Internal Network Request

Medium
Category
Server-Side Request Forgery
Content
ports:
      - "127.0.0.1:8080:8080"
    healthcheck:
      test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:8080/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
      interval: 30s
      timeout: 5s
      retries: 5
Confidence
70% confidence
Finding
Code issues a request to a loopback, link-local, or private-range host. This can reach internal services not meant to be exposed and is a common SSRF pivot.

Session Persistence

Medium
Category
Rogue Agent
Content
TMR

  systemctl --user daemon-reload
  systemctl --user enable --now autotask-mcp-update.timer

  echo ""
  echo "Systemd user timer installed."
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
systemctl --user enable --now autotask-mcp-update.timer

  echo ""
  echo "Systemd user timer installed."
  echo "  Check status: systemctl --user status autotask-mcp-update.timer"
  echo "  To remove later, run: ./scripts/cron_uninstall.sh"
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
removed=false

if [[ "$OS" == "Darwin" ]]; then
  PLIST_LABEL="com.autotask-mcp.weekly-update"
  PLIST_PATH="$HOME/Library/LaunchAgents/${PLIST_LABEL}.plist"

  if [[ -f "$PLIST_PATH" ]]; then
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
removed=false

if [[ "$OS" == "Darwin" ]]; then
  PLIST_LABEL="com.autotask-mcp.weekly-update"
  PLIST_PATH="$HOME/Library/LaunchAgents/${PLIST_LABEL}.plist"

  if [[ -f "$PLIST_PATH" ]]; then
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
removed=false

if [[ "$OS" == "Darwin" ]]; then
  PLIST_LABEL="com.autotask-mcp.weekly-update"
  PLIST_PATH="$HOME/Library/LaunchAgents/${PLIST_LABEL}.plist"

  if [[ -f "$PLIST_PATH" ]]; then
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
removed=false

if [[ "$OS" == "Darwin" ]]; then
  PLIST_LABEL="com.autotask-mcp.weekly-update"
  PLIST_PATH="$HOME/Library/LaunchAgents/${PLIST_LABEL}.plist"

  if [[ -f "$PLIST_PATH" ]]; then
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.