T09 · Insecure Skill Coding Practices
- Location
scripts/analyze_pdf_folder.py:92- Finding
Extracted PDF contents are persisted in plaintext through an unsafe predictable output path
- Content
View full analysis
Vulnerability Details
File Location:
scripts/analyze_pdf_folder.py:92-117
Vulnerability Type: Plaintext sensitive-data storage and unsafe predictable-file overwrite
Risk Level: MediumVulnerable 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.jsoninside the user-supplied directory. This creates a persistent plaintext copy of potentially confidential document contents.The fixed output path is opened in
wmode, which truncates an existing destination. Python's ordinaryopen()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
- A victim selects a PDF directory ...[truncated 1583 chars]
- Remediation
View remediation
Remediation Suggestions
- Return the structured JSON through standard output instead of retaining extracted document contents on disk.
- If persistent output is required, obtain explicit user consent and clearly document the destination, retained fields, retention period, and deletion procedure.
- Reject symbolic-link destinations using
os.path.islink()and perform race-resistant opening with platform-appropriate flags such asO_NOFOLLOW. - Avoid silent truncation. Use exclusive creation (
O_CREAT | O_EXCL) or obtain explicit confirmation before replacing an existing file. - Create the output with restrictive permissions, such as owner read/write only, and verify directory ownership and permissions.
- Write to a securely created temporary file and atomically replace the intended destination after successful serialization.
- Minimize retained information by omitting absolute paths and full document text when they are not necessary.
- Provide automatic cleanup or deletion after the classification and reporting stages complete.
