T05 · Unauthorized Access and Privilege Escalation
- Location
scripts/execute.py:274- Finding
Candidate-Controlled Target Path Allows File Modification Outside the Approved Scope
- Content
View full analysis
Vulnerability Details
File Location:
scripts/execute.py:274-303
Vulnerability Type: Missing path authorization and scope validation
Risk Level: HighVulnerable Code
python target_file = Path(candidate["target_path"]).expanduser().resolve() if not target_file.exists() or not target_file.is_file(): result = { "status": "error", "modified": False, "reason": f"target file not found: {target_file}", } output_path = Path(args.output).expanduser().resolve() if args.output else paths["executions"] / f"{run_id}-{candidate['id']}.json" artifact = { "schema_version": SCHEMA_VERSION, "lane": ranking_artifact.get("lane", "generic-skill"), "run_id": run_id, "stage": "executed", "status": "error", "created_at": utc_now_iso(), "candidate_id": candidate["id"], "target_path": str(target_file), "result": result, "truth_anchor": str(output_path), } write_json(output_path, artifact) update_state( state_root, run_id=run_id, stage="executed", status="error", target_path=str(target_file), truth_anchor=str(output_path), extra={"candidate_id": candidate["id"]}, ) print(str(output_path)) return 1 backup_path = paths["executions"] / "backups" / run_id / f"{candidate['id']}-{target_file.name}" backup_file(target_file, backup_path) plan = candidate.get("execution_plan", {}) action = plan.get("action") handler = ACTION_HANDLERS.get(action) if handler is not None: result = handler(target_file, plan)Technical Analysis
The file that will be modified is derived directly from the candidate-controlled
target_path. Callingresolve()canonicalizes the path but does not authorize it. The implementation does not verify that the resolved path:- Matches the trusted
ranking_artifact["target"]["path"].
...[truncated 2004 chars]
- Matches the trusted
- Remediation
View remediation
Remediation Suggestions
-
Derive the destination from a trusted project root rather than accepting an unrestricted absolute candidate path.
-
Require the candidate target to exactly match the target declared by the trusted ranking artifact, where the workflow expects a single target.
-
Canonicalize both the approved root and candidate path, then enforce containment:
python approved_root = Path(configured_project_root).resolve(strict=True) target_file = Path(candidate["target_path"]).expanduser().resolve(strict=True) try: target_file.relative_to(approved_root) except ValueError: raise ValueError("Candidate target is outside the approved project root") -
Reject symbolic links and verify the target using descriptor-based, no-follow filesystem operations where supported.
-
Validate ranking artifacts against a strict schema and authenticate artifacts when they cross a trust boundary.
-
Apply an explicit extension or file allowlist appropriate to the selected action.
-
Store backups in a directory with restrictive permissions and avoid backing up unauthorized targets.
-
Add negative tests covering absolute paths,
..traversal, symlinks, mismatches with the ranking target, and paths outside the approved root.
-
