T05 · Unauthorized Access and Privilege Escalation
- Location
references/6.context.md:349- Finding
Caller-controlled file paths can disclose arbitrary local files to an external model provider
- Content
View full analysis
Vulnerability Details
File Location:
references/6.context.md, lines 349–418
Vulnerability Type: Arbitrary local file read followed by external transmission
Risk Level: HighVulnerable Code
python @dataclass class FileContext: uploaded_files: list[dict] @wrap_model_call def inject_file_context( request: ModelRequest, handler: Callable[[ModelRequest], ModelResponse] ) -> ModelResponse: """Inject context about files user has uploaded this session.""" uploaded_files = request.runtime.context.uploaded_files try: base_dir = os.path.dirname(os.path.abspath(__file__)) except Exception as e: import ipynbname import os notebook_path = ipynbname.path() base_dir = os.path.dirname(notebook_path) file_sections = [] for file in uploaded_files: name, ftype = "", "" path = file.get("path") if path: base_filename = os.path.basename(path) stem, ext = os.path.splitext(base_filename) name = stem or base_filename ftype = (ext.lstrip(".") if ext else None) content_list = [f"Name: {name}"] if ftype: content_list.append(f"Type: {ftype}") abs_path = path if os.path.isabs(path) else os.path.join(base_dir, path) content_block = "" if abs_path and os.path.exists(abs_path): try: with open(abs_path, "r", encoding="utf-8") as f: content_block = f.read() except Exception as e: content_block = f"[File read error '{abs_path}': {e}]" else: content_block = "[File path missing or not found]" section = ( f"---\n" f"{chr(10).join(content_list)}\n\n" f"{content_block}\n" ...[truncated 3081 chars]- Remediation
View remediation
Remediation Suggestions
-
Replace caller-provided filesystem paths with opaque, server-issued upload identifiers.
-
Store uploads beneath a dedicated root directory with restrictive permissions.
-
Resolve and validate each requested path before opening it:
python from pathlib import Path UPLOAD_ROOT = Path("/srv/app/uploads").resolve() def resolve_uploaded_file(file_id: str) -> Path: candidate = (UPLOAD_ROOT / file_id).resolve(strict=True) if candidate == UPLOAD_ROOT or UPLOAD_ROOT not in candidate.parents: raise PermissionError("File is outside the upload directory") if candidate.is_symlink() or not candidate.is_file(): raise PermissionError("Invalid uploaded file") return candidate -
Reject absolute paths,
..traversal components, device files, and symbolic links. -
Allowlist expected text formats and enforce strict per-file and aggregate size limits.
-
Read files incrementally rather than loading unlimited content into memory.
-
Detect and redact likely credentials before constructing a remote prompt.
-
Clearly notify users and obtain consent before sending uploaded content to an external model provider.
-
Use a locally hosted model or an approved no-retention endpoint when processing sensitive documents.
-
Avoid returning raw local paths and exception details to downstream model messages.
-
