T09 · Insecure Skill Coding Practices
- Location
scripts/prep_session.py:14- Finding
Path Traversal Permits Unauthorized Local JSON Data Access
- Content
View full analysis
Vulnerability Details
File Location:
scripts/prep_session.py, lines 14-19
Vulnerability Type: Path traversal and insufficient file-access validation
Risk Level: HighVulnerable Code
python def load_client_data(client_name): """Load client data from isolated storage.""" client_file = os.path.join(COACHING_DIR, f"{client_name.lower().replace(' ', '_')}.json") if os.path.exists(client_file): with open(client_file, 'r') as f: return json.load(f) return {"sessions": [], "goals": [], "commitments": []}The
client_namevalue originates from the required--clientcommand-line argument and is incorporated into a filesystem path. Replacing spaces and converting input to lowercase does not remove path separators, absolute path prefixes, or..traversal components.os.path.join()also discardsCOACHING_DIRwhen its subsequent argument is an absolute path. Consequently, a caller can direct the script to another readable JSON file instead of a record contained in the intended coaching directory.The loaded object is subsequently processed and selected values from its
sessionsandcommitmentsfields are printed. This directly contradicts the documented guarantees of client isolation and local coaching-data confidentiality.Technical Analysis
The vulnerability is caused by treating a human-readable client name as a trusted filename without canonicalization or containment validation. There is no check that the resolved file:
- Remains beneath
COACHING_DIR. - Has a filename from an approved character set.
- Does not contain
..components or path separators. - Is not an absolute path.
- Is not reached through a symbolic link that escapes the storage directory.
Exploitation is constrained to files readable by the operating-system account running the skill, whose names can be addressed with the automatically appended
.jsonsuffix, and whose ...[truncated 1889 chars]- Remains beneath
- Remediation
View remediation
Remediation Suggestions
-
Do not derive storage paths directly from untrusted client names. Assign each client an opaque, application-generated identifier such as a UUID and maintain a validated name-to-identifier mapping.
-
If filename derivation is unavoidable, enforce a strict allowlist such as letters, digits, underscores, and hyphens. Reject absolute paths, path separators, empty names,
.components, and..components. -
Resolve and verify path containment before opening the file:
python from pathlib import Path import re COACHING_PATH = Path(COACHING_DIR).resolve() def load_client_data(client_name): if not re.fullmatch(r"[A-Za-z0-9_-]+", client_name): raise ValueError("Invalid client identifier") candidate = (COACHING_PATH / f"{client_name}.json").resolve() if candidate.parent != COACHING_PATH: raise ValueError("Client path escapes coaching storage") if candidate.is_file(): with candidate.open("r", encoding="utf-8") as file: data = json.load(file) if not isinstance(data, dict): raise ValueError("Invalid client record") return data return {"sessions": [], "goals": [], "commitments": []} -
Protect against symbolic-link escapes. Where supported, reject symlinks and open files using platform facilities equivalent to
O_NOFOLLOW; additionally verify the opened file's identity and location. -
Apply restrictive permissions to the coaching directory and records, limiting access to the owning user.
-
Validate the complete JSON schema before processing or displaying values, and handle parsing errors without exposing unrelated file contents or implementation details.
-
Add tests covering absolute paths, traversal sequences, nested separators, encoded or alternate separators, symbolic links, malformed JSON, and attempts to select another client's record.
-
