fix(chat/sdk): validate cwd against sandbox prefix to fix CodeQL alert

CodeQL traces session_id → cwd → os.makedirs/open as uncontrolled path.
Add realpath + startswith check against /tmp/copilot- prefix directly in
write_transcript_to_tempfile so CodeQL recognizes the sanitization.

Also resolve the prefix with realpath for macOS where /tmp → /private/tmp.
This commit is contained in:
Zamil Majdy
2026-02-13 15:49:30 +04:00
parent 8dfd0a77a0
commit d0f0c32e70
2 changed files with 56 additions and 26 deletions

View File

@@ -154,6 +154,9 @@ def _sanitize_id(raw_id: str) -> str:
return _SAFE_ID_RE.sub("", raw_id)
_SAFE_CWD_PREFIX = os.path.realpath("/tmp/copilot-")
def write_transcript_to_tempfile(
transcript_content: str,
session_id: str,
@@ -166,15 +169,16 @@ def write_transcript_to_tempfile(
Returns the absolute path to the file, or ``None`` on failure.
"""
try:
os.makedirs(cwd, exist_ok=True)
safe_id = _sanitize_id(session_id)[:8]
jsonl_path = os.path.join(cwd, f"transcript-{safe_id}.jsonl")
# Validate cwd is under the expected sandbox prefix (CodeQL sanitizer).
real_cwd = os.path.realpath(cwd)
if not real_cwd.startswith(_SAFE_CWD_PREFIX):
logger.warning(f"[Transcript] cwd outside sandbox: {cwd}")
return None
# Defence-in-depth: ensure the resolved path stays inside cwd
if not os.path.realpath(jsonl_path).startswith(os.path.realpath(cwd)):
logger.warning(f"[Transcript] Path escaped cwd: {jsonl_path}")
return None
try:
os.makedirs(real_cwd, exist_ok=True)
safe_id = _sanitize_id(session_id)[:8]
jsonl_path = os.path.join(real_cwd, f"transcript-{safe_id}.jsonl")
with open(jsonl_path, "w") as f:
f.write(transcript_content)

View File

@@ -85,26 +85,52 @@ class TestReadTranscriptFile:
class TestWriteTranscriptToTempfile:
def test_writes_file_and_returns_path(self, tmp_path):
cwd = str(tmp_path / "workspace")
result = write_transcript_to_tempfile(VALID_TRANSCRIPT, "sess-1234-abcd", cwd)
assert result is not None
assert os.path.isfile(result)
assert result.endswith(".jsonl")
with open(result) as f:
assert f.read() == VALID_TRANSCRIPT
"""Tests use /tmp/copilot-* paths to satisfy the sandbox prefix check."""
def test_creates_parent_directory(self, tmp_path):
cwd = str(tmp_path / "new" / "dir")
def test_writes_file_and_returns_path(self):
cwd = "/tmp/copilot-test-write"
try:
result = write_transcript_to_tempfile(
VALID_TRANSCRIPT, "sess-1234-abcd", cwd
)
assert result is not None
assert os.path.isfile(result)
assert result.endswith(".jsonl")
with open(result) as f:
assert f.read() == VALID_TRANSCRIPT
finally:
import shutil
shutil.rmtree(cwd, ignore_errors=True)
def test_creates_parent_directory(self):
cwd = "/tmp/copilot-test-mkdir"
try:
result = write_transcript_to_tempfile(VALID_TRANSCRIPT, "sess-1234", cwd)
assert result is not None
assert os.path.isdir(cwd)
finally:
import shutil
shutil.rmtree(cwd, ignore_errors=True)
def test_uses_session_id_prefix(self):
cwd = "/tmp/copilot-test-prefix"
try:
result = write_transcript_to_tempfile(
VALID_TRANSCRIPT, "abcdef12-rest", cwd
)
assert result is not None
assert "abcdef12" in os.path.basename(result)
finally:
import shutil
shutil.rmtree(cwd, ignore_errors=True)
def test_rejects_cwd_outside_sandbox(self, tmp_path):
cwd = str(tmp_path / "not-copilot")
result = write_transcript_to_tempfile(VALID_TRANSCRIPT, "sess-1234", cwd)
assert result is not None
assert os.path.isdir(cwd)
def test_uses_session_id_prefix(self, tmp_path):
cwd = str(tmp_path)
result = write_transcript_to_tempfile(VALID_TRANSCRIPT, "abcdef12-rest", cwd)
assert result is not None
assert "abcdef12" in os.path.basename(result)
assert result is None
# --- validate_transcript ---