T09 · Insecure Skill Coding Practices
- Location
scripts/validate_report_definition.py:435- Finding
Unrestricted file references permit access outside approved report storage
- Content
View full analysis
Vulnerability Details
File Location:
scripts/validate_report_definition.py:435-443,scripts/validate_report_definition.py:485-500, andscripts/validate_report_definition.py:592-600
Vulnerability Type: Improper path restriction and arbitrary local file reference
Risk Level: MediumVulnerable Code
python def resolve_reference_path(reference: str, input_path: Path) -> Path: candidate = Path(reference) if candidate.is_absolute(): return candidate cwd_candidate = Path.cwd() / candidate if cwd_candidate.exists(): return cwd_candidate.resolve() return (input_path.parent / candidate).resolve()python query_file = value.get("queryFile") if query_file is not None: if not is_non_empty_string(query_file): add_error(errors, f"{path}.queryFile must be a non-empty string when present") return query_file_hash = validate_sha256_string( data_source.get("queryFileSha256"), f"{path.rsplit('.', 1)[0]}.queryFileSha256", errors, ) resolved_path = resolve_reference_path(str(query_file).strip(), input_path) if not resolved_path.exists() or not resolved_path.is_file(): add_error(errors, f"{path}.queryFile must point to an existing file: {resolved_path}") return if query_file_hash is not None: actual_hash = sha256_file(resolved_path) if actual_hash != query_file_hash: add_error( errors, f"{path.rsplit('.', 1)[0]}.queryFileSha256 does not match the contents of {resolved_path}", )python def validate_preview(value: object, input_path: Path, errors: list[str]) -> None: if not isinstance(value, dict): add_error(errors, "definition.preview must be an object when present") return artifact_ref = validate_required_string(value, "artifactRef", errors, " ...[truncated 2507 chars]- Remediation
View remediation
Remediation Suggestions
- Define separate, explicit allowlisted roots for query files and preview artifacts.
- Reject absolute paths supplied by report definitions.
- Resolve the candidate and configured root with
Path.resolve(strict=True), then requirecandidate.is_relative_to(root). - Reject symlinks or verify that the fully resolved target remains beneath the approved root.
- Require a regular file and apply expected extension or content-type restrictions to preview artifacts.
- Avoid returning resolved sensitive paths in validation errors exposed to untrusted users.
- Ensure downstream delivery independently repeats the same canonical-path containment check rather than trusting prior validation.
- Run validation and report delivery under a minimally privileged service account that cannot read unrelated secrets.
