T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/auto_link.py:117
- Finding
- Shell Command Injection Through Generated Repair Script## Vulnerability Details **File Location**: `scripts/auto_link.py`, lines 13–15 and 117–123 **Vulnerability Type**: Shell command injection through unsafe script generation **Risk Level**: Medium The application inserts untrusted Markdown link content directly into a generated Bash script without rejecting line breaks or other control characters. **Source of untrusted content (`scripts/auto_link.py`, lines 13–15):** ```python def extract_links(content): """提取 [[双向链接]] 中的笔记名""" return re.findall(r'\[\[([^\]]+)\]\]', content) ``` **Vulnerable script-generation operation (`scripts/auto_link.py`, lines 117–123):** ```python # 生成修复建议(dry_run=false 时输出可执行脚本) if not dry_run and (dead_links or orphans): fix_script = vault / ".claude_fix_suggestions.sh" with open(fix_script, 'w', encoding='utf-8') as f: f.write("#!/bin/bash\n# Claude-Obsidian 修复建议(手动确认后执行)\n\n") for dl in dead_links: f.write(f"# 在 {dl['file'].relative_to(vault)} 中将 [[{dl['link']}]] 替换为 [[{dl['suggestion']}]]\n") ``` ### Technical Analysis `extract_links()` obtains link text directly from Markdown files inside the user-selected vault. Its regular expression uses the character class `[^\]]+`, which excludes closing square brackets but does not exclude newline or carriage-return characters. The extracted value is subsequently stored in `dl['link']` and interpolated into `.claude_fix_suggestions.sh`. Although the generated content is intended to be a shell comment, an embedded newline can terminate the comment. The next line is then interpreted as a shell command if the generated file is executed. The derived `dl['suggestion']` value is also unsafe because operations such as `strip()`, `replace()`, and `lower()` do not remove embedded line breaks. ### Attack Path 1. An attacker supplies, shares, or causes the user to import a Markdown file into the scanned vault. 2. The Markdown file contains a crafte ...[truncated 1404 chars]
- Remediation
- ## Remediation Suggestions 1. **Do not generate executable shell files from vault content.** Generate a non-executable Markdown, JSON, or plain-text report instead. This is the preferred remediation because the file currently contains only comments and does not require shell semantics. 2. **Reject control characters in all untrusted fields.** Validate extracted links and relative paths before using them in generated output: ```python def validate_single_line(value): if any(ch in value for ch in ("\n", "\r", "\x00")): raise ValueError("Link contains prohibited control characters") return value ``` 3. **Make report-only behavior the default.** Require an explicit option to generate any executable artifact rather than generating `.claude_fix_suggestions.sh` whenever `--dry-run` is absent. 4. **Use structured repair data.** Store the source file, original link, and suggested replacement as JSON fields. A separate trusted tool can consume that data without invoking a shell. 5. **If shell generation is unavoidable, avoid embedding data in comments or command text.** Pass validated values as arguments to a fixed program and quote each value with a proven shell-escaping function such as `shlex.quote()`. Shell quoting alone should supplement, not replace, rejection of newline and control characters. 6. **Apply safe file permissions.** Create generated reports without executable permission and avoid a `.sh` extension unless executable behavior is genuinely required. 7. **Add regression tests** covering links with newline characters, carriage returns, shell metacharacters, command substitutions, backticks, quotes, and crafted filenames. Verify that these inputs are rejected or represented only in a non-executable structured format.
