Back to skill

Security audit

Publish Website Traefik

Security checks for vulnerabilities and agentic risk

Overview

This skill is meant to publish and delete Docker-hosted static sites, but its Docker and deletion scripts are under-scoped and could be unsafe if made runnable.

Review this skill carefully before installing. It is not deceptive, but it expects Docker authority and includes deletion behavior; only use it in an isolated environment after adding strict subdomain validation, a confined deployment directory, protected state-file permissions, and an explicit delete confirmation or backup workflow.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/deploy_site.sh:1
Finding
Unvalidated Subdomain Allows Docker Compose YAML Injection<![CDATA[ ## Vulnerability Details **File Location**: `scripts/deploy_site.sh:1` **Vulnerability Type**: Docker Compose YAML injection through unvalidated input **Risk Level**: High ### Vulnerable Code ```bash SUBDOMAIN=\"$2\" DOMAIN=\"sites.friendify.cloud\" FULL_DOMAIN=\"${SUBDOMAIN}.${DOMAIN}\" TEMP_DIR=\"/tmp/traefik-deploy-${SUBDOMAIN}-$(date +%s)\" mkdir -p \"$TEMP_DIR\" || { echo \"Failed to create temporary directory\"; exit 1; } cat <<EOF > \"$TEMP_DIR/docker-compose.yml\" version: '3.8' services: nginx: image: nginx:alpine container_name: \"${SUBDOMAIN}-web\" labels: - \"traefik.enable=true\" - \"traefik.http.routers.${SUBDOMAIN}-router.rule=Host(\`${FULL_DOMAIN}\`)\" - \"traefik.http.routers.${SUBDOMAIN}-router.entrypoints=websecure\" - \"traefik.http.routers.${SUBDOMAIN}-router.tls=true\" - \"traefik.http.routers.${SUBDOMAIN}-router.tls.certresolver=le\" - \"traefik.http.services.${SUBDOMAIN}-service.loadbalancer.server.port=80\" networks: - web networks: web: external: true EOF pushd \"$TEMP_DIR\" || { echo \"Failed to change directory to $TEMP_DIR\"; exit 1; } docker compose up -d || { echo \"Failed to start docker compose services\"; popd; exit 1; } ``` ### Technical Analysis The second positional argument is accepted as `SUBDOMAIN` without validation and interpolated directly into a generated Docker Compose YAML document. Shell quoting around the variable does not protect the structure of the generated YAML because variable expansion occurs while processing the heredoc. A subdomain containing quote characters, line breaks, or YAML syntax can potentially terminate an existing scalar and inject additional Compose properties. Depending on the crafted structure, an attacker could attempt to introduce properties such as: - Host filesystem bind mounts - An attacker-controlled container command or entry point - Additional environment variables - Privileged container mode - Ho ...[truncated 1792 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Enforce a strict DNS-label allowlist before using the subdomain: ```bash if [[ ! "$SUBDOMAIN" =~ ^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$ ]]; then echo "Invalid subdomain" exit 1 fi ``` 2. Explicitly reject line breaks, carriage returns, tabs, quotes, slashes, backslashes, and control characters. 3. Generate Compose configuration using a structured YAML or JSON serializer rather than interpolating untrusted values into a heredoc. 4. Use an independently generated deployment identifier for Compose project, service, container, and temporary-directory names. Do not derive operational identifiers directly from user input. 5. Validate the generated Compose file before execution: ```bash docker compose -f "$TEMP_DIR/docker-compose.yml" config --quiet ``` 6. Run deployments through a narrowly scoped service rather than granting general Docker permissions to callers. 7. Pin the Nginx image to a reviewed immutable digest. 8. Restore real newline bytes in the script and add tests covering malicious quotes, control characters, multiline values, and oversized subdomains before making it executable. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/delete_site.sh:1
Finding
Untrusted Deployment State Controls Recursive Directory Deletion<![CDATA[ ## Vulnerability Details **File Location**: `scripts/delete_site.sh:1` **Vulnerability Type**: Unvalidated path usage and unsafe recursive deletion **Risk Level**: Medium ### Vulnerable Code ```bash SUBDOMAIN=\"$1\" DEPLOYMENTS_FILE=\"/data/.openclaw/workspace/publish-website-traefik/deployments.json\" DEPLOYMENT_INFO=$(jq -r --arg subdomain \"$SUBDOMAIN\" '.[$subdomain]' \"$DEPLOYMENTS_FILE\") if [ \"$DEPLOYMENT_INFO\" == \"null\" ]; then echo \"Deployment for subdomain '$SUBDOMAIN' not found.\" exit 1 fi TEMP_DIR=$(echo \"$DEPLOYMENT_INFO\" | jq -r '.temp_dir') echo \"Deleting deployment for $SUBDOMAIN...\" if [ -d \"$TEMP_DIR\" ]; then echo \"Changing to $TEMP_DIR to bring down services.\" pushd \"$TEMP_DIR\" || { echo \"Failed to change directory to $TEMP_DIR\"; exit 1; } docker compose down -v || { echo \"Failed to bring down docker compose services\"; popd; exit 1; } popd echo \"Services for $SUBDOMAIN brought down.\" rm -rf \"$TEMP_DIR\" echo \"Temporary directory $TEMP_DIR removed.\" fi ``` ### Technical Analysis The deletion script obtains `temp_dir` from `deployments.json` and uses it as both: - The working directory for `docker compose down -v` - The target of `rm -rf` The path is not canonicalized or checked against an expected deployment root. The script also does not verify path ownership, permissions, directory identity, or whether the Compose project belongs to the requested deployment. Consequently, anyone able to modify or corrupt the deployment state file can direct the script to an unrelated directory. The recursive deletion executes with the privileges of the user running the script. Before deletion, Docker Compose also processes configuration from the attacker-selected directory, which may cause unintended Docker resources to be removed. The scripts currently contain literal `\n` sequences and do not execute normally as packaged. This unsafe path flow becomes operational if the e ...[truncated 1291 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Store all deployment directories under a dedicated root with restrictive permissions, such as `/var/lib/publish-website-traefik/deployments`. 2. Canonicalize the stored path using `realpath` and require it to be a direct child of that deployment root. 3. Reject empty paths, `/`, the deployment root itself, relative paths, paths containing traversal components, and paths outside the approved root. 4. Verify that the directory is owned by the expected service account and is not an untrusted symbolic link. 5. Store an independently generated deployment identifier rather than accepting an arbitrary directory path from JSON. 6. Pass an explicit reviewed Compose file and project name: ```bash docker compose \ --project-name "$SAFE_PROJECT_ID" \ --file "$SAFE_DIR/docker-compose.yml" \ down -v ``` 7. Validate that the Compose file and project metadata correspond to the requested deployment before teardown. 8. Protect `deployments.json` with restrictive ownership and permissions, use atomic updates, and validate its schema before consuming it. 9. Replace unrestricted recursive deletion with a guarded cleanup function that fails closed when any invariant is not satisfied. 10. Restore proper newline encoding and test deletion against malicious state entries before enabling execution. ]]>
Vulnerability Patterns
  • 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
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (2)

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
The primary behavior shown matches the declared deployment purpose: it creates a Docker Compose configuration for nginx, configures Traefik labels for the requested subdomain, starts the container, copies static files into nginx, and produces a URL under sites.friendify.cloud. However, the declared description says the skill provides deploy, list, and delete functions, while this code chunk only implements deployment. Since the task is to compare the supplied code chunk itself, that alone is not necessarily a mismatch unless the code contradicts the description. The meaningful undeclared behavior is that it persists deployment metadata to a hard-coded workspace file path, which is access to an additional local resource not described. Aside from that, the code is aligned with the stated purpose.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
This markdown file describes a delete command that stops and removes a Docker container and its resources, which is a destructive operation affecting service availability. While the action is named 'delete,' the documentation does not include a clear warning or caution about irreversibility, downtime, or verifying the target subdomain before proceeding.

Static analysis

No suspicious patterns detected.