T09 · Insecure Skill Coding Practices
- Location
SKILL.md:48- Finding
Unquoted User-Controlled Arguments May Enable Shell Command Injection
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md, lines 48–64
Vulnerability Type: Shell command injection through unsafe argument interpolation
Risk Level: MediumVulnerable Code
bash python scripts/calculate_retirement.py <出生日期> <性别> <身份类型> <月工资> <城市> <就业类型> <是否含公积金>The documented examples use the same unquoted command construction:
bash python scripts/calculate_retirement.py 1985-06-15 male worker 15000 北京 employee true python scripts/calculate_retirement.py 1985-06-15 male worker 15000 北京 flexibleTechnical Analysis
The Skill directs the agent to construct a shell command using values collected from the user, including textual values such as city, gender, job type, and employment type. These arguments are not quoted, escaped, or explicitly validated before being placed into the command.
The Python script itself does not invoke a shell and does not independently execute injected commands. The exposure arises when an agent or integration follows
SKILL.mdby interpolating user-provided values into a command string and then submits that string to a shell. Shell metacharacters such as semicolons, command substitutions, pipes, redirections, or logical operators could consequently be interpreted as shell syntax rather than as literal argument content.Although several parameters are expected to be enums, the Python entry point does not strictly validate all of them. An unknown city is accepted and mapped to default city data, and unknown employment types fall through to employee calculations. This increases the likelihood that crafted textual input can reach command construction without rejection.
Attack Path
- An attacker supplies a crafted textual field, such as a city containing shell syntax:
text Beijing; touch /tmp/retirement_skill_injected # - The agent inserts the value into the documented command withou ...[truncated 1403 chars]
- An attacker supplies a crafted textual field, such as a city containing shell syntax:
- Remediation
View remediation
Remediation Suggestions
-
Invoke the calculator through a subprocess argument array rather than a shell command string:
python subprocess.run( [ sys.executable, "scripts/calculate_retirement.py", birth_date, gender, job_type, str(monthly_salary), city, employment_type, str(include_housing_fund).lower(), ], shell=False, check=True, ) -
Explicitly state in
SKILL.mdthat implementations must not useshell=True,os.system, or string-based shell execution with collected values. -
Validate every input before execution:
- Require dates to match
YYYY-MM-DDand represent valid calendar dates. - Restrict gender to
maleorfemale. - Restrict job type to
workerorcadre. - Restrict employment type to
employeeorflexible. - Restrict the housing-fund option to
trueorfalse. - Require salary to be finite, non-negative, and within a reasonable upper bound.
- Restrict city to a supported allowlist or pass it only as a literal argument array element.
- Require dates to match
-
Add equivalent validation to
scripts/calculate_retirement.pyso unsafe or unsupported values are rejected even when callers bypass the documented workflow. -
If a shell is unavoidably required, apply a proven platform-specific quoting function to every argument. Argument-array execution remains the preferred mitigation.
-
