T09 · Insecure Skill Coding Practices
- Location
native_run.py:31- Finding
Unrestricted Shell Command Execution from Chat-Controlled Input
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill openly provides local command execution, but it does so with broad, weakly controlled shell access that should be reviewed carefully before installation.
Install only in a tightly trusted, isolated environment. Anyone or anything able to trigger this skill, or reach the localhost runner with the embedded token, may be able to run local commands and see their output. Prefer a version with explicit command allowlists, per-use confirmation, generated per-install credentials, sandboxing, and audit logging.
native_run.py:31Unrestricted Shell Command Execution from Chat-Controlled Input
native_run.py:11Hardcoded Shared Secret Protecting the Native Command Runner
This service exposes arbitrary shell execution over HTTP without a clearly justified constrained use case, effectively acting as a remote command runner. Even though it binds to localhost, local malware, browser-based local service abuse, SSRF from local apps, or any process on the machine could use it to execute commands if the token is known or recovered.
The service performs dangerous native actions without any user confirmation, approval flow, or interactive warning, making accidental or unauthorized execution far easier. In an agent or skill context, this is especially risky because a downstream component could trigger command execution implicitly once it can reach the endpoint and supply the token.
This is a classic tool-parameter abuse issue: untrusted request data is passed directly into a powerful execution primitive. The use of shell=True magnifies the risk by allowing shell metacharacters, chaining, redirection, and expansion, so an attacker can execute far more than an intended single command.
# Run the command
try:
output = subprocess.check_output(
payload["command"],
shell=True,
stderr=subprocess.STDOUT,
The skill takes user-controlled text from context.message, strips a prefix, and forwards the remainder as a command to a native runner endpoint with task 'native_run'. This creates a direct command-execution bridge with no validation, allowlist, authentication boundary, or safety controls, so an attacker who can invoke the skill can likely execute arbitrary OS-level actions via the local service.
The skill exposes native command execution on the local gateway machine, but the usage trigger is only described as a message that 'matches the configured pattern' with an example of free-form command text. This ambiguity increases the risk that unintended or overly broad inputs will activate arbitrary command execution, which is especially dangerous because the skill returns command output and runs on Windows locally.
The code executes attacker-controlled input from an HTTP request using subprocess.check_output with shell=True, which enables arbitrary shell command execution on the host. Because the command comes directly from payload["command"] with no validation or restriction, any caller with the token can run system commands, read files, modify the environment, or pivot further.
# Run the command
try:
output = subprocess.check_output(
payload["command"],
shell=True,
stderr=subprocess.STDOUT,
Returning raw command output over HTTP can expose sensitive system information such as environment variables, file contents, credentials, keys, hostnames, and network configuration. Since the output is entirely determined by the executed command, this endpoint can be used for direct data exfiltration as well as command execution.
The skill silently transmits user-supplied command text to a backend HTTP service without any disclosure, confirmation, or trust boundary warning. Because the payload is a command destined for a native runner, this is especially risky: users may not realize their input is being handed to an execution service, increasing the chance of abuse, accidental destructive actions, or social-engineering-driven execution.
The code makes a request to an internal localhost service, which is an internal network interaction and can expose privileged local functionality to remote or less-trusted callers of the skill. While this is not classic user-controlled SSRF because the destination is hardcoded, it still acts as a proxy into a sensitive local service and expands access to internal-only capabilities.
if (!command) return '❌ No command provided.';
try {
const resp = await axios.post(
'http://localhost:8080/?token=272d22dec98da63a3362c6dc0a9c0eebf2aa9ed96d21775d',
{ task: 'native_run', command }
);
The description 'Run an arbitrary command' is explicitly unconstrained and advertises unrestricted command execution as the skill's purpose. In the provided context, this is not merely vague wording: the task comment states that the command is injected from the chat message, which makes the broad scope directly security-relevant because it enables arbitrary OS command execution from untrusted input.
The comment describes a health-check endpoint, implying a specific endpoint intended for health status. In practice, do_GET unconditionally returns 200 and "native-run online" for any GET request path, so the documented intent is narrower than the actual behavior.
No suspicious patterns detected.