T09 · Insecure Skill Coding Practices
- Location
scripts/publish.py:91- Finding
Incomplete privacy scanning can publish unreviewed sensitive files to a public repository
- Content
View full analysis
Vulnerability Details
File Location:
scripts/publish.py:91-102,scripts/publish.py:166-197, andscripts/publish.py:221-236
Vulnerability Type: Incomplete security validation followed by automatic public disclosure
Risk Level: HighVulnerable Code
The upload routine recursively collects every file under the supplied directory:
python def upload_dir(token, owner, repo, local_dir, file_order=None): """递归上传整个目录。 file_order: 优先上传的文件列表(先根目录 README,再子目录) """ all_files = [] for root, dirs, files in os.walk(local_dir): for f in files: full = os.path.join(root, f) rel = os.path.relpath(full, local_dir) all_files.append(rel)The privacy scanner excludes selected filenames and silently skips files that cannot be decoded as UTF-8:
python ignore_files = ignore_files or [] issues = [] for root, dirs, files in os.walk(local_dir): for f in files: full = os.path.join(root, f) # 跳过规则定义自身(脚本和 SKILL.md) if f in ignore_files: continue try: with open(full, 'r', encoding='utf-8') as fp: content = fp.read() except (UnicodeDecodeError, IOError): continue for pat, desc in patterns: m = re.search(pat, content) if m: issues.append((full, desc, m.group()[:60])) return issuesPublication explicitly excludes all files named
publish.pyorSKILL.mdfrom review, creates a public repository, and then uploads the complete directory:python issues = privacy_scan(local_dir, ignore_files=['publish.py', 'SKILL.md']) if issues: print(f'❌ 发现 {len(issues)} 个潜在问题:') for path, desc, snippet in issues: print(f' {path}: {desc} -> {snippet}') print('请先修复再发布。') sys.exit(1) print(' ✅ 干净') create_repo(token, repo, description, priv ...[truncated 3917 chars]- Remediation
View remediation
Remediation Suggestions
-
Use one immutable, validated manifest
- Enumerate candidate files once.
- Scan the exact bytes that will be uploaded.
- Store approved paths, hashes, and file sizes in a manifest.
- Upload only entries whose hashes still match the reviewed manifest.
-
Fail closed
- Treat decoding failures, unreadable files, broken links, and unsupported file types as blocking findings.
- Never interpret an unscannable file as clean.
- Require explicit, per-file approval if binary publication is necessary.
-
Remove broad filename exclusions
- Do not exclude every file named
publish.pyorSKILL.md. - If scanner rule definitions cause self-matches, suppress only the exact known lines or findings rather than the entire file.
- Ensure every uploaded file receives equivalent validation.
- Do not exclude every file named
-
Constrain directory traversal
- Exclude
.git, environment files, editor metadata, caches, temporary files, build outputs, and credential stores by default. - Add an explicit allowlist of intended publication paths or file types.
- Detect symbolic links and reject links that resolve outside the canonical source directory.
- Exclude
-
Improve secret detection
- Add generic credential assignment checks for terms such as
api_key,secret,password, andtoken. - Detect common cloud, package registry, database, SSH, and private-key formats.
- Use entropy-based checks or an established secret-scanning tool.
- Report every finding rather than only the first match for each pattern and file.
- Add generic credential assignment checks for terms such as
-
Require explicit approval
- Display the complete upload manifest, repository owner, repository name, visibility, and all scan findings.
- Require a deliberate confirmation before the first network request.
- Do not rely solely on the absence of regex matches as consent to publish.
-
Default to private visibility
- Create the repository ...[truncated 506 chars]
-
