T09 · Insecure Skill Coding Practices
- Location
scripts/zk.py:164- Finding
Shell Command Injection in Editor Launcher
- Content
View full analysis
Vulnerability Details
File Location:
scripts/zk.py, lines 164–166
Vulnerability Type: OS command injection through shell interpolation
Risk Level: HighVulnerable Code
python def _open_in_editor(path: Path): editor = os.environ.get("EDITOR", "nano") os.system(f'{editor} "{path}"')Technical Analysis
The
_open_in_editorfunction constructs a shell command by directly interpolating theEDITORenvironment variable and the note path into a string passed toos.system(). Becauseos.system()invokes a command shell, shell metacharacters in either value may be interpreted as executable syntax.The
EDITORvalue is entirely environment-controlled. The note path is also influenced by theZK_VAULTenvironment variable or the--vaultcommand-line option. Wrapping the path in double quotes is insufficient because a malicious path can contain embedded quotation marks, command substitutions, or other shell syntax.The vulnerable function is reached by the
new,promote, andmoccommands unless the user supplies--no-edit.Attack Path
- An attacker gains the ability to influence the process environment, a wrapper script, shell configuration, automation configuration, or command-line arguments.
- The attacker places shell syntax in
EDITOR,ZK_VAULT, or--vault. For example, a maliciousEDITORvalue could append an additional shell command. - The user invokes
zk new,zk promote, orzk mocwithout--no-edit. - The command creates or selects a note and calls
_open_in_editor(). _open_in_editor()interpolates the attacker-influenced value into a shell command.os.system()passes the resulting command to the shell, which executes the injected syntax with the privileges of the user running the CLI.
Impact Assessment
Successful exploitation permits arbitrary local command execution with the current user's privileges. The attacker could read or modify files accessible to that us ...[truncated 310 chars]
- Remediation
View remediation
Remediation Suggestions
Avoid invoking a shell. Parse the configured editor command into an argument vector and execute it directly:
python import shlex import subprocess def _open_in_editor(path: Path): editor = os.environ.get("EDITOR", "nano") command = shlex.split(editor) if not command: raise ValueError("EDITOR must specify an executable") subprocess.run([*command, str(path)], check=False)Additional hardening measures:
- Validate that
EDITORresolves to an expected executable before launching it. - Where flexible editor arguments are unnecessary, use a strict allowlist or require
EDITORto contain only an executable path. - Resolve and validate the vault path before use, particularly when it originates from
ZK_VAULTor--vault. - Avoid
shell=True,os.system(), and all string-built shell commands for paths or configuration values. - Add regression tests using editor values and vault paths containing spaces, quotes, semicolons, command substitutions, and other shell metacharacters. Verify that these values are passed as literal arguments and never executed as shell syntax.
- Validate that
