T09 · Insecure Skill Coding Practices
Error
- Location
- SKILL.md:28
- Finding
- Command Injection Through Unvalidated Deployment Parameters<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 28–34 and 45–68 **Vulnerability Type**: Shell command injection through unvalidated user-controlled values **Risk Level**: High ### Vulnerable Code The skill instructs the agent to collect deployment parameters from the user, including project paths, image names, image tags, SSH information, remote deployment directories, environment files, volume mappings, and container runtime parameters. These values are then interpolated directly into shell commands: ```bash cd <项目根目录路径> docker build -t <镜像仓库地址>:<镜像标签> -f <Dockerfile路径> . docker push <镜像仓库地址>:<镜像标签> ``` The same pattern is used for operations on the remote server: ```bash cd <服务器部署目录> docker pull <镜像仓库地址>:<镜像标签> docker stop tpaip-server && docker rm tpaip-server docker run -d \ --name tpaip-server \ --restart unless-stopped \ -p 8080:8080 \ --env-file .env \ -v ./data:/app/data \ <镜像仓库地址>:<镜像标签> ``` ### Technical Analysis The skill treats user-supplied deployment information as command fragments without specifying any validation, canonicalization, shell escaping, or safe argument-passing requirements. Values such as the project directory, Dockerfile path, image repository, image tag, remote deployment directory, environment-file path, volume mappings, and additional container parameters can therefore cross a command boundary when interpreted by a shell. For example, if a deployment directory or image-tag value contains shell metacharacters such as a semicolon, command substitution, a newline, or a logical operator, an agent that follows the documented template by constructing a shell command may execute the injected expression as a separate command. Quoting alone would not be sufficient unless it is implemented consistently and appropriate to the shell. The safer design is to avoid constructing shell command strings and instead invoke processes with explicit argument arrays after validating each value against its ex ...[truncated 2434 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Use structured process invocation** - Invoke Docker and related utilities through argument arrays rather than dynamically constructed shell strings. - Do not use shell evaluation functions such as `eval`, `sh -c`, or equivalent wrappers for deployment values. 2. **Apply strict allowlist validation** - Permit image tags only when they match an expected expression such as `^[A-Za-z0-9_][A-Za-z0-9._-]{0,127}$`. - Validate registry and image names using Docker reference grammar. - Validate ports as integers in the range `1–65535`. - Permit only explicitly supported Docker runtime options instead of accepting an arbitrary parameter string. - Reject command separators, control characters, newlines, command substitutions, and shell redirection syntax in every externally supplied value. 3. **Secure path handling** - Canonicalize project, Dockerfile, deployment, environment-file, and volume paths before use. - Require paths to remain under approved base directories. - Reject traversal outside approved roots and reject unexpected symbolic links where relevant. - Pass paths as individual arguments and quote them safely if shell execution is unavoidable. 4. **Restrict container parameters** - Represent ports, environment files, and volume mappings as separate validated fields. - Do not append free-form user-provided text to `docker run`. - Prohibit dangerous options such as `--privileged`, host PID or network namespaces, Docker socket mounts, arbitrary device access, and unrestricted host filesystem mounts unless separately authorized. 5. **Reduce deployment privileges** - Use a dedicated deployment identity with access limited to the required repository and application. - Avoid granting unrestricted Docker socket access where possible. - Use rootless containers, a constrained deployment service, or narrowly scoped privileged automation. - Restrict SSH keys by host, source, comm ...[truncated 726 chars]
