mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-02-13 08:14:58 -05:00
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:
@@ -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)
|
||||
|
||||
@@ -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 ---
|
||||
|
||||
Reference in New Issue
Block a user