Back to skill

Security audit

deployment-kit

Security checks for vulnerabilities and agentic risk

Overview

This is a disclosed VPS deployment helper, but it needs review because it can restart or kill broad system processes and handles runtime state and Telegram credentials in fragile ways.

Install only on a VPS or staging host you own and after reviewing the scripts. Before production use, restrict service names to an allowlist, remove or replace the pkill -f fallback, store logs and heartbeat files in a private runtime directory, scope sudoers to specific units, and consider a safer Telegram notification method that does not expose the bot token in process arguments.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/deploy.sh:21
Finding

Unvalidated Service Name Enables Broad Regex-Based Process Termination

Content
View full analysis
/dev/null | grep -q "$SVC"; then echo " target: systemd service '$SVC' via sudo systemctl restart" if [ "$DRY" = "1" ]; then echo " [dry-run] no changes made"; exit 0; fi read -r -p " Restart systemd service '$SVC'? [y/N] " ans [ "$ans" = "y" ] || [ "$ans" = "Y" ] || { echo " cancelled"; exit 1; } sudo systemctl restart "$SVC" && echo " systemd: restarted" else echo " target: kill matching processes (pkill -f '$SVC') + relaunch via nohup" if [ "$DRY" = "1" ]; then echo " [dry-run] no changes made"; exit 0; fi read -r -p " Kill processes matching '$SVC' and relaunch? [y/N] " ans [ "$ans" = "y" ] || [ "$ans" = "Y" ] || { echo " cancelled"; exit 1; } pkill -f "$SVC" 2>/dev/null; sleep 2 ``` ### Technical Analysis The service name is accepted directly from a command-line argument and is not restricted to a safe service-name syntax. It is passed to both `grep` and `pkill -f`, where it is interpreted as a regular expression rather than as a literal, exact service identifier. The systemd detection is therefore unreliable: a crafted expression may match an unrelated unit and direct execution into the wrong branch. If no unit is detected, `pkill -f` applies the attacker-controlled expression to complete process command lines. Expressions such as `.*`, broad substrings, or deliberately constructed alternatives can match and terminate numerous unrelated processes. The confirmation prompt reduces accidental execution but does not neutralize the vulnerability. An operator may approve the action based on the displayed service name without understanding that it is a regular expression or that `pkill -f` can match unrelated command lines. ### Attack Path 1. An a ...[truncated 1247 chars]
Remediation
View remediation
&2 exit 2 ;; esac ``` 2. Query systemd using an exact unit name rather than parsing `list-units` with a regular expression: ```bash UNIT="${SVC%.service}.service" if systemctl show "$UNIT" >/dev/null 2>&1; then sudo systemctl restart "$UNIT" fi ``` 3. Do not use `pkill -f` for service lifecycle management. Prefer systemd, another process supervisor, or a securely maintained PID file. 4. If a PID file is used, place it in a private runtime directory, verify that it is a regular file owned by the expected user, validate that its content is a numeric PID, and confirm the process identity before sending a signal. 5. If literal process matching is unavoidable, avoid regular-expression interpretation and ensure the match uniquely identifies the intended executable. Operator confirmation should remain as defense in depth, not as the primary security control. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/deploy.sh:37
Finding

Predictable and Attacker-Influenced Temporary File Paths

Content
View full analysis
/tmp/$SVC.log 2>&1 & echo "4) Log: tail /tmp/$SVC.log" ``` From `scripts/watchdog.sh`: ```bash HB="/tmp/${SVC}_HB.txt" [ ! -f "$HB" ] && { echo "HB mangler — genstarter $SVC"; bash "$(dirname "$0")/deploy.sh" "$SVC"; bash "$(dirname "$0")/notify.sh" "⚠️ $SVC: HB manglede — genstartet"; exit; } ``` ### Technical Analysis The deployment log and heartbeat file are placed directly in the shared `/tmp` directory using predictable names derived from an unvalidated service name. The shell redirection used for the log follows symbolic links. A local attacker who can create `/tmp/.log` before deployment may point that path at another file. When the script opens the path with `>`, the target is truncated if the deployment account has permission to modify it. The watchdog also treats the existence and modification time of a predictable `/tmp/_HB.txt` path as authoritative health information. It does not verify ownership, file type, permissions, or whether the file was produced by the intended service. Another local user may therefore create or update the heartbeat path to suppress legitimate recovery, or interfere with the path to induce false failure handling. Service-name validation is also absent, making path construction less trustworthy. Shell quoting prevents ordinary shell word splitting, but it does not make shared, predictable temporary paths safe. ### Attack Path #### Log symlink attack 1. A local attacker learns or predicts the service name. 2. Before deployment, the attacker creates `/tmp/.log` as a symbolic link to a file writable by the deployment account. 3. An operator runs the deployment script and confi ...[truncated 1459 chars]
Remediation
View remediation
&2 exit 2 ;; esac ``` 3. Prefer systemd logging through the journal rather than manually creating predictable log files. For non-systemd execution, create logs securely in an application-owned directory with restrictive permissions. 4. Avoid following symbolic links when creating files. Use secure creation mechanisms such as `mktemp` in a private directory, or create files through a helper that uses `O_CREAT | O_EXCL | O_NOFOLLOW`. 5. Store heartbeat state under `/run/` or another directory owned by the service account and inaccessible to unrelated users. 6. Before trusting a heartbeat file, verify that it is a regular file, is owned by the expected service account, has restrictive permissions, and resides in the expected private directory. 7. Use a process supervisor's native health and restart facilities where possible instead of shared temporary heartbeat files. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/notify.sh:10
Finding

Telegram Bot Token Exposed Through Process Command-Line Arguments

Content
View full analysis
/dev/null ``` ### Technical Analysis The Telegram bot token is embedded directly in the URL passed as a command-line argument to `curl`. While the token is required as part of Telegram's Bot API URL, command-line arguments may be observable through process-inspection interfaces and tools on systems whose process-visibility policy permits other users to inspect them. The script correctly avoids hardcoding the token and supports a permission-restricted environment file, but that storage protection does not prevent transient disclosure after `curl` is launched. The message and chat identifier are also passed as command-line arguments through `-d`, although the bot token is the most security-sensitive value. The exposure window is limited by the duration of the request, but repeated watchdog alerts create additional opportunities for a local observer to capture the process arguments. ### Attack Path 1. The notification script loads `TG_BOT_TOKEN` from the environment or `~/.config/tg-alert.env`. 2. It launches `curl` with the token embedded in the URL argument. 3. While the request is active, a local user or monitoring process with permission to inspect the curl process reads its command-line arguments. 4. The observer extracts the bot token from the Telegram API URL. 5. The stolen token is reused to interact with the Telegram Bot API as that bot. Successful exploitation depends on the operating system's process-visibility restrictions and the attacker's local access. ### Impact Assessment A disclosed token allows an attacker to impersonate the Telegram bot within the capabilities granted by Telegram's Bot API. Potential effects include ...[truncated 339 chars]
Remediation
View remediation
/dev/null ``` Confirm the behavior and process exposure characteristics on the target platform. 2. Run the notifier under a dedicated, least-privileged service account and configure the host to restrict cross-user process inspection, such as an appropriate `/proc` `hidepid` policy on Linux. 3. Retain mode `0600` on the credential file and ensure its parent directory is not accessible to unrelated users. 4. Use `--data-urlencode` for message and chat fields so special characters are encoded consistently. 5. Rotate the Telegram bot token if there is reason to believe process arguments have been observable, and monitor the bot for unauthorized activity. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (18)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The documentation describes a broad deployment and monitoring suite, but the finding indicates the real behavior is much narrower and includes hard-coded verification and process-killing fallback behavior. This mismatch is dangerous because operators may trust the advertised safeguards and capabilities while the actual implementation performs different, potentially disruptive actions on the host.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill advertises shell-capable operational behavior but does not declare an explicit tool scope such as permissions or allowed-tools. That omission weakens reviewability and containment because consumers cannot easily tell that the skill is intended to execute privileged deployment actions like restarts and process management.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
65% 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.

Content

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

md
---
name: "deployment-kit"
description: "Deploy and maintain services on a VPS with 1 command: build → restart → verify → monitor with heartbeat + Telegram alerts. Complete DevOps package: systemd units, nginx reverse proxy, cron @reboot, watchdog restarts, deploy scripts. WARNING: runs systemd restarts, sudo, nohup/setsid and changes runtime state — only use on services you own, test on staging first."
metadata: {"deployment-kit": {"requires": {"bins": ["systemctl", "sudo", "curl", "nohup", "setsid"], "network": ["https://api.telegram.org"], "env": ["TG_BOT_TOKEN", "TG_CHAT_ID"], "files": ["~/.config/tg-alert.env"]}}}
---

Session Persistence

Medium
Category
Rogue Agent
Confidence
65% 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.

Content

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

md
---
name: "deployment-kit"
description: "Deploy and maintain services on a VPS with 1 command: build → restart → verify → monitor with heartbeat + Telegram alerts. Complete DevOps package: systemd units, nginx reverse proxy, cron @reboot, watchdog restarts, deploy scripts. WARNING: runs systemd restarts, sudo, nohup/setsid and changes runtime state — only use on services you own, test on staging first."
metadata: {"deployment-kit": {"requires": {"bins": ["systemctl", "sudo", "curl", "nohup", "setsid"], "network": ["https://api.telegram.org"], "env": ["TG_BOT_TOKEN", "TG_CHAT_ID"], "files": ["~/.config/tg-alert.env"]}}}
---

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The header documents bash deploy.sh --dry-run <service-name> as valid usage, but the script assigns SVC from $1 before checking for --dry-run. In practice, invoking the documented dry-run form causes SVC to be set to --dry-run, which then affects the default workdir computation and initial validation flow, contradicting the stated usage contract.

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 37)May include surrounding context.

md
# 1-command deploy: build → restart → verify
# Usage: bash deploy.sh <service-name> [workdir]
#        bash deploy.sh --dry-run <service-name>   # preview only, no changes
# ⚠️ WARNING: restarts services (sudo systemctl / pkill / nohup) — can cause downtime.
#    Only run on services you own. Test on staging first. Have a rollback plan.
#    A confirmation prompt is shown before any destructive action.
SVC="${1:?Service-name missing}"

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 63)May include surrounding context.

md
# 1-command deploy: build → restart → verify
# Usage: bash deploy.sh <service-name> [workdir]
#        bash deploy.sh --dry-run <service-name>   # preview only, no changes
# ⚠️ WARNING: restarts services (sudo systemctl / pkill / nohup) — can cause downtime.
#    Only run on services you own. Test on staging first. Have a rollback plan.
#    A confirmation prompt is shown before any destructive action.
SVC="${1:?Service-name missing}"

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 · scripts/deploy.sh (reported line 5)May include surrounding context.

sh
# 1-command deploy: build → restart → verify
# Usage: bash deploy.sh <service-name> [workdir]
#        bash deploy.sh --dry-run <service-name>   # preview only, no changes
# ⚠️ WARNING: restarts services (sudo systemctl / pkill / nohup) — can cause downtime.
#    Only run on services you own. Test on staging first. Have a rollback plan.
#    A confirmation prompt is shown before any destructive action.
SVC="${1:?Service-name missing}"

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 · scripts/deploy.sh (reported line 24)May include surrounding context.

sh
# 1-command deploy: build → restart → verify
# Usage: bash deploy.sh <service-name> [workdir]
#        bash deploy.sh --dry-run <service-name>   # preview only, no changes
# ⚠️ WARNING: restarts services (sudo systemctl / pkill / nohup) — can cause downtime.
#    Only run on services you own. Test on staging first. Have a rollback plan.
#    A confirmation prompt is shown before any destructive action.
SVC="${1:?Service-name missing}"

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
86% confidence
Finding

The script performs sudo systemctl restart "$SVC" using a service name derived from user input. Although the argument is quoted and protected from shell injection, this still enables an operator or calling automation to restart arbitrary systemd units if sudo policy permits it, which can disrupt critical services or be abused in overly broad sudo configurations.

Content

Scanner excerpt · scripts/deploy.sh (reported line 28)May include surrounding context.

sh
if [ "$DRY" = "1" ]; then echo "  [dry-run] no changes made"; exit 0; fi
  read -r -p "  Restart systemd service '$SVC'? [y/N] " ans
  [ "$ans" = "y" ] || [ "$ans" = "Y" ] || { echo "  cancelled"; exit 1; }
  sudo systemctl restart "$SVC" && echo "  systemd: restarted"
else
  echo "  target: kill matching processes (pkill -f '$SVC') + relaunch via nohup"
  if [ "$DRY" = "1" ]; then echo "  [dry-run] no changes made"; exit 0; fi

Session Persistence

Medium
Category
Rogue Agent
Confidence
91% confidence
Finding

Using nohup to launch python3 "$DIR/server.py" creates a persistent background process outside a supervised service manager. In this deployment context, that can leave unmanaged long-lived processes running from user-controlled directories, making it easier to accidentally or intentionally persist modified code and evade normal operational controls.

Content

Scanner excerpt · scripts/deploy.sh (reported line 35)May include surrounding context.

sh
read -r -p "  Kill processes matching '$SVC' and relaunch? [y/N] " ans
  [ "$ans" = "y" ] || [ "$ans" = "Y" ] || { echo "  cancelled"; exit 1; }
  pkill -f "$SVC" 2>/dev/null; sleep 2
  # Intentional daemonization: nohup keeps the process running after shell exit
  nohup python3 "$DIR/server.py" >/tmp/$SVC.log 2>&1 &
  echo "  nohup: restarted (pid $!)"
fi

Session Persistence

Medium
Category
Rogue Agent
Confidence
65% 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.

Content

Scanner excerpt · scripts/deploy.sh (reported line 36)May include surrounding context.

sh
[ "$ans" = "y" ] || [ "$ans" = "Y" ] || { echo "  cancelled"; exit 1; }
  pkill -f "$SVC" 2>/dev/null; sleep 2
  # Intentional daemonization: nohup keeps the process running after shell exit
  nohup python3 "$DIR/server.py" >/tmp/$SVC.log 2>&1 &
  echo "  nohup: restarted (pid $!)"
fi
sleep 3

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

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

Content

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

md
#!/bin/bash
# Telegram alert: BOT_TOKEN + CHAT_ID in environment or file
# 🔒 Secrets: set permissions with: chmod 600 ~/.config/tg-alert.env
#    Never commit the token in git/logs/shell history.
TOKEN="${TG_BOT_TOKEN:-}"
CHAT="${TG_CHAT_ID:-}"

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

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

Content

Scanner excerpt · scripts/notify.sh (reported line 3)May include surrounding context.

sh
#!/bin/bash
# Telegram alert: BOT_TOKEN + CHAT_ID in environment or file
# 🔒 Secrets: set permissions with: chmod 600 ~/.config/tg-alert.env
#    Never commit the token in git/logs/shell history.
TOKEN="${TG_BOT_TOKEN:-}"
CHAT="${TG_CHAT_ID:-}"

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/notify.sh (reported line 10)May include surrounding context.

sh
[ -z "$TOKEN" ] && [ -f ~/.config/tg-alert.env ] && source ~/.config/tg-alert.env
[ -z "$TOKEN" ] && { echo "Set TG_BOT_TOKEN"; exit 1; }
MSG="${1:-⚠️ Alert}"
curl -s --max-time 10 "https://api.telegram.org/bot$TOKEN/sendMessage" \
  -d "chat_id=$CHAT" -d "text=$MSG" > /dev/null

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/notify.sh (reported line 10)May include surrounding context.

sh
[ -z "$TOKEN" ] && [ -f ~/.config/tg-alert.env ] && source ~/.config/tg-alert.env
[ -z "$TOKEN" ] && { echo "Set TG_BOT_TOKEN"; exit 1; }
MSG="${1:-⚠️ Alert}"
curl -s --max-time 10 "https://api.telegram.org/bot$TOKEN/sendMessage" \
  -d "chat_id=$CHAT" -d "text=$MSG" > /dev/null

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

This code automatically invokes deploy.sh to restart the service when the heartbeat file is missing or stale. While it logs locally with echo, there is no user-facing warning, confirmation, or embedded documentation explaining that this watchdog will perform a potentially disruptive restart action.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script's comments, parameter error text, and status/alert messages are written in Danish, which imposes a specific language for operational output. There is no indication that the skill is region-specific or that users can opt into this locale, so it may violate language/locale policy expectations.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.