T05 · Unauthorized Access and Privilege Escalation
- Location
scripts/main.py:76- Finding
Unrestricted Inventory Path Permits Arbitrary File Read and Overwrite
- Content
View full analysis
Vulnerability Details
File Location:
scripts/main.py:76-98, with the user-controlled argument introduced atscripts/main.py:381and passed to the vulnerable code atscripts/main.py:406
Vulnerability Type: Path traversal and missing filesystem access-control validation
Risk Level: HighVulnerable Code
python def __init__(self, data_path: Optional[str] = None): self.data_path = data_path or self.DEFAULT_DATA_PATH self.data = self._load_data() def _load_data(self) -> Dict: """Load data file""" if os.path.exists(self.data_path): with open(self.data_path, 'r', encoding='utf-8') as f: return json.load(f) return { "settings": { "default_safety_days": 7, "default_lead_time_days": 3, "prediction_lookback_days": 30 }, "reagents": [] } def _save_data(self): """Save data file""" os.makedirs(os.path.dirname(self.data_path), exist_ok=True) with open(self.data_path, 'w', encoding='utf-8') as f: json.dump(self.data, f, ensure_ascii=False, indent=2)The unvalidated path originates from the command line:
python parser.add_argument('--data-path', help='Data file path')It is then passed directly to the inventory implementation:
python predictor = InventoryPredictor(args.data_path)Technical Analysis
The
--data-pathvalue is under user control and is used directly byos.path.exists,open, andos.makedirs. The implementation does not canonicalize the path, enforce a permitted base directory, reject traversal components, or protect against symbolic-link redirection.Consequently, paths such as
/outside/workspace/file.jsonor paths containing../can escape the intended inventory workspace. A symbolic link inside an allowed-looking directory could likewise resolve to a file elsewhere.This behavior directly contra ...[truncated 2125 chars]
- Remediation
View remediation
Remediation Suggestions
- Define a single trusted workspace root and resolve it before processing user input.
- Resolve the requested path with
Path.resolve()before any existence check, read, directory creation, or write. - Verify that the resolved path is a descendant of the trusted workspace using
Path.is_relative_to()on supported Python versions or a saferelative_to()check. - Reject absolute paths outside the workspace and traversal paths that resolve outside it.
- Reject symbolic links for both the target and relevant parent components, or open files using platform facilities that prevent symbolic-link following.
- Restrict accepted targets to regular files with the expected
.jsonextension. - Write updates atomically to a temporary file inside the same approved directory, validate the serialized data, and then replace the intended inventory file.
- Apply restrictive file permissions so inventory data is not exposed to unrelated local users.
- Return a clear validation error before constructing
InventoryPredictorwhen the path is outside the authorized root. - Add tests covering absolute-path escape,
../traversal, symbolic-link escape, nonexistent parent directories, and valid in-workspace paths.
