T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/analyze_pdf_folder.py:92
- Finding
- Extracted PDF contents are persisted in plaintext through an unsafe predictable output path## Vulnerability Details **File Location**: `scripts/analyze_pdf_folder.py:92-117` **Vulnerability Type**: Plaintext sensitive-data storage and unsafe predictable-file overwrite **Risk Level**: Medium ### Vulnerable Code ```python documents.append({ "file_name": file_name, "file_path": pdf_path, "text": text }) return { "success": True, "folder_path": folder_path, "document_count": len(documents), "documents": documents, "errors": errors } def main(): if len(sys.argv) < 2: print("❌ 使用方法:python extract_pdf_folder.py <本地PDF目录路径>") sys.exit(1) folder_path = sys.argv[1] result = analyze_pdf_folder(folder_path) # Write to file instead of stdout to avoid encoding issues output_file = os.path.join(folder_path, "_extracted_texts.json") with open(output_file, "w", encoding="utf-8") as f: json.dump(result, f, ensure_ascii=False, indent=2) ``` ### Technical Analysis The script collects each PDF's filename, absolute path, and complete extracted text, then serializes that information to a fixed file named `_extracted_texts.json` inside the user-supplied directory. This creates a persistent plaintext copy of potentially confidential document contents. The fixed output path is opened in `w` mode, which truncates an existing destination. Python's ordinary `open()` also follows symbolic links. The implementation does not check whether the destination already exists, whether it is a symbolic link, or whether its ownership and permissions are safe. It also does not use exclusive creation, restrictive permissions, or atomic replacement. Although the Skill documentation describes the extraction stage as returning structured results, it does not clearly disclose that all extracted document text will be retained in a plaintext sidecar file. ### Attack Path 1. A victim selects a PDF directory ...[truncated 1583 chars]
- Remediation
- ## Remediation Suggestions 1. Return the structured JSON through standard output instead of retaining extracted document contents on disk. 2. If persistent output is required, obtain explicit user consent and clearly document the destination, retained fields, retention period, and deletion procedure. 3. Reject symbolic-link destinations using `os.path.islink()` and perform race-resistant opening with platform-appropriate flags such as `O_NOFOLLOW`. 4. Avoid silent truncation. Use exclusive creation (`O_CREAT | O_EXCL`) or obtain explicit confirmation before replacing an existing file. 5. Create the output with restrictive permissions, such as owner read/write only, and verify directory ownership and permissions. 6. Write to a securely created temporary file and atomically replace the intended destination after successful serialization. 7. Minimize retained information by omitting absolute paths and full document text when they are not necessary. 8. Provide automatic cleanup or deletion after the classification and reporting stages complete.
