T09 · Insecure Skill Coding Practices
- Location
src/index.ts:146- Finding
Shell Command Injection Through Unescaped Attachment and Configuration Values
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This is a coherent Stardots image-upload skill, but its implementation uses unsafe shell execution and weak attachment-path controls that could expose local files or run unintended commands.
Review before installing. Only use this with non-sensitive images and trusted attachment sources, and prefer a version that replaces shell-based curl with a native upload client, validates attachment handles and file contents, avoids putting secrets on command lines, and asks for confirmation before uploading to Stardots.
src/index.ts:146Shell Command Injection Through Unescaped Attachment and Configuration Values
src/index.ts:58Arbitrary Local File Upload Through Unvalidated Attachment Paths
The skill invokes a general shell execution tool to perform an upload even though a direct HTTP client or dedicated upload API would suffice. Because the shell command interpolates attacker-influenced values such as file paths and config values, this introduces command-injection risk and grants the skill far more capability than needed.
The skill constructs a shell command with interpolated values, including a user-controlled attachment path, and executes it via exec. This creates command-injection risk and grants unnecessary shell capability for a task that should use a native HTTP client or safe subprocess argument API.
The skill explicitly backs up images to stardots.io, a third-party cloud service, but the description does not clearly warn users that their images leave the local environment and are transmitted to an external provider. This can lead to unintentional disclosure of sensitive images, especially if users trigger the skill based only on brief phrases like '备份到stardots' without understanding the privacy implications.
The skill returns user-visible messages only in Chinese, including setup and invocation guidance, without offering a language option or documenting a justified locale restriction. This can violate language/locale policy when a specific language is imposed by default.
The skill transmits user-provided image attachments to a third-party cloud service, but the code does not present an explicit disclosure or confirmation at the point of action. This is a privacy and data-handling issue because users may not realize their local files are being sent off-device to an external service.
The skill reads API credentials not only from its explicit runtime config but also from environment variables and a local file in the user's home directory. For a simple image-upload skill, this broadens access to sensitive local secrets beyond the immediate user request and creates unnecessary credential exposure and implicit trust in host-local data sources.
The comment frames the behavior as merely using curl for upload, but the actual mechanism is a full exec capability that can run arbitrary shell commands. This mismatch is dangerous because it obscures the true privilege level of the skill and can mislead reviewers into underestimating the attack surface.
The skill sends files and authentication material to an external domain, which is expected for an upload feature but still constitutes a real data egress path. In this context the danger is elevated because uploads happen automatically from attachments and are coupled with opaque credential sourcing and shell execution.
const nonce = this.generateNonce();
const sign = this.generateSign(timestamp, nonce, config.apiSecret);
// 使用 exec 工具调用 curl 上传
const command = `curl -s -X PUT "https://api.stardots.io/openapi/file/upload" \
-H "x-stardots-timestamp: ${timestamp}" \
-H "x-stardots-nonce: ${nonce}" \
-H "x-stardots-key: ${config.apiKey}" \
The shell command embeds sensitive API headers and a local file path into an exec invocation without any explicit disclosure. Besides transparency concerns, command execution may expose secrets through process listings, logs, error traces, or tool telemetry depending on the host environment.
The regex trigger "上传.*stardots" is broad enough to match many ordinary user requests that merely mention uploading and Stardots, which can cause unintended skill activation. Because the skill has both network and filesystem permissions and performs backup/upload behavior, accidental invocation could result in unexpected file access or data transfer.
The regex trigger "stardots.*备份" is ambiguous and lacks invocation boundaries, so it may activate on incidental mentions of Stardots and backup in the same sentence rather than an explicit command. In this skill's context, ambiguous triggering is more dangerous because activation can initiate cloud upload behavior using network and filesystem capabilities.
Natural-language strings in the skill, including user-facing error and guidance messages, are written only in Chinese with no indication that the user can choose another language. This is a language policy concern because it imposes a locale/language choice without explicit opt-in or documented justification.
The skill uploads user-provided image attachments to a third-party cloud service, but the code provides no explicit consent, warning, or confirmation that files will leave the local environment. In agent contexts, silent external transmission of attachments is privacy-relevant and may violate user expectations or policy.
The skill harvests API credentials from environment variables and a user-local config file even though its declared interface does not establish a need for broad host secret or filesystem access. In an agent setting, this expands trust boundaries and can unintentionally consume sensitive host secrets outside explicit user-provided configuration, making secret misuse or unexpected disclosure more likely.
The code silently reads API credentials from environment variables and a local config file without notifying the user. Even if intended for convenience, undisclosed access to host secrets and files is sensitive behavior in an agent skill because users may not expect the skill to inspect those locations.
The skill invokes an external shell command to perform uploads without any visible warning or confirmation. While the more severe issue is command injection, the transparency problem itself matters because users are not informed that shell execution is occurring on the host.
The skill transmits local image content and associated authentication headers to an external service at api.stardots.io. External transmission is expected for an upload skill, but in this context it remains security-relevant because it moves user data off-host and combines it with automatically sourced credentials.
const sign = this.generateSign(timestamp, nonce, config.apiSecret);
// 使用 exec 工具调用 curl 上传
const command = `curl -s -X PUT "https://api.stardots.io/openapi/file/upload" \
-H "x-stardots-timestamp: ${timestamp}" \
-H "x-stardots-nonce: ${nonce}" \
-H "x-stardots-key: ${config.apiKey}" \
The natural-language instructions and usage examples are presented in Chinese only, and there is no indication that the skill supports alternative languages or is intentionally restricted to a Chinese-speaking context. This can violate language/locale policy when a specific language is imposed without user opt-in.
The skill silently reads API credentials from environment variables and local configuration sources without making that behavior explicit to users or deployers in code flow. While this is less severe than direct exfiltration, it reduces transparency around what sensitive local data the skill can access.
Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.
"license": "MIT",
"dependencies": {},
"devDependencies": {
"@types/node": "^18.0.0",
"typescript": "^5.0.0"
}
}
Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.
"dependencies": {},
"devDependencies": {
"@types/node": "^18.0.0",
"typescript": "^5.0.0"
}
}
All listed trigger phrases are Chinese-only, which effectively constrains invocation to a specific language. The manifest does not indicate that this locale restriction is optional, user-selected, or justified as a region-specific skill.
No suspicious patterns detected.