T09 · Insecure Skill Coding Practices
- Location
scripts/doc_fetch.py:193- Finding
Arbitrary Local File Read Through Untrusted Index Paths
- Content
View full analysis
Dict[str, Any]: """Load the index file.""" with open(index_path, 'r', encoding='utf-8') as f: return json.load(f) ``` ```python def fetch_lines(filepath: str, start: int, end: int) -> str: """Retrieve a specified range of lines from a file.""" try: with open(filepath, 'r', encoding='utf-8', errors='ignore') as f: lines = f.readlines() ``` ```python filepath = file_info['filepath'] print(f'📄 File: {file_info["filename"]}') print(f'📍 Path: {filepath}') print(f'📝 Total lines: {file_info.get("total_lines", "?")}') print('=' * 60) # List sections if args.list: print(list_sections(file_info)) return 0 # Retrieve a section if args.section: section = find_section_in_file(file_info, args.section) if not section: print(f'❌ Section not found: {args.section}') print(list_sections(file_info)) return 1 print(f'📑 Section: {section.get("title")}') print(f'📍 Location: lines {section.get("start_line")}-{section.get("end_line")}') print('-' * 60) print(fetch_section(filepath, section, args.context)) return 0 # Retrieve a line range if args.lines: start, end = parse_line_range(args.lines) print(f'📍 Line range: {start}-{end}') print('-' * 60) print(fetch_lines(filepath, start, end)) return 0 # Retrieve all content if args.all: print(f'📄 Full content, up to {args.max_lines} lines:') print('-' * 60) print(fetch_all(filepath, args.max_lines)) return 0 ``` From `scripts/doc_search. ...[truncated 3699 chars]- Remediation
View remediation
Path: trusted_root = Path(root).resolve(strict=True) candidate = Path(indexed_path) if candidate.is_absolute(): raise ValueError("Absolute paths are not permitted in index entries") resolved = (trusted_root / candidate).resolve(strict=True) if not resolved.is_relative_to(trusted_root): raise ValueError("Indexed path escapes the trusted document root") if not resolved.is_file(): raise ValueError("Indexed path is not a regular file") return resolved ``` 3. **Store relative paths in generated indexes** - Modify `doc_indexer.py` so index entries contain paths relative to the indexed root rather than absolute paths. - Resolve those relative paths only after applying the containment check. 4. **Handle symbolic links explicitly** - Either reject symbolic links entirely or resolve them and verify that their final targets remain under the trusted root. 5. **Validate index structure** - Enforce a schema that constrains required properties and types. - Reject unknown or malformed entries. - Apply reasonable limits to the number of files, section ranges, and path lengths. 6. **Avoid trusting externally supplied indexes** - Regenerate an index from a user-approved source directory where practical. - If indexes must be reusable across trust bounda ...[truncated 615 chars]
