MCPcopy Index your code
hub / github.com/github/spec-kit / test_load_rejects_path_traversal

Method test_load_rejects_path_traversal

tests/test_workflows.py:4132–4168  ·  view source on GitHub ↗

``RunState.load`` validates ``run_id`` before touching the filesystem. Without this guard, a value like ``../escape`` passed via ``specify workflow resume`` would interpolate path-traversal segments into the lookup path. ``state_path.exists()`` would probe ar

(self, project_dir, malicious_run_id)

Source from the content-addressed store, hash-verified

4130 ],
4131 )
4132 def test_load_rejects_path_traversal(self, project_dir, malicious_run_id):
4133 """``RunState.load`` validates ``run_id`` before touching the
4134 filesystem.
4135
4136 Without this guard, a value like ``../escape`` passed via
4137 ``specify workflow resume`` would interpolate path-traversal
4138 segments into the lookup path. ``state_path.exists()`` would
4139 probe arbitrary paths the process can read (a file-existence
4140 oracle) and ``json.load`` would happily parse attacker-planted
4141 JSON from outside ``.specify/workflows/runs/``. The check must
4142 fire *before* the path is built — ``__init__``'s identical
4143 regex on ``state_data["run_id"]`` fires too late.
4144 """
4145 from specify_cli.workflows.engine import RunState
4146
4147 # Plant a state.json *outside* the legitimate ``runs/`` directory
4148 # at the location ``../escape`` would traverse to, so a missing
4149 # guard would surface as a successful load rather than a
4150 # ``FileNotFoundError`` (which would be ambiguous with the
4151 # not-found case).
4152 runs_dir = project_dir / ".specify" / "workflows" / "runs"
4153 runs_dir.mkdir(parents=True, exist_ok=True)
4154 attacker_dir = project_dir / ".specify" / "workflows" / "escape"
4155 attacker_dir.mkdir(exist_ok=True)
4156 (attacker_dir / "state.json").write_text(
4157 json.dumps(
4158 {
4159 "run_id": "pwned",
4160 "workflow_id": "attacker-owned",
4161 "status": "created",
4162 }
4163 ),
4164 encoding="utf-8",
4165 )
4166
4167 with pytest.raises(ValueError, match="Invalid run_id"):
4168 RunState.load(malicious_run_id, project_dir)
4169
4170 @pytest.mark.parametrize(
4171 "bad_run_id",

Callers

nothing calls this directly

Calls 1

loadMethod · 0.45

Tested by

no test coverage detected