fix(V-009): reject Windows drive-letter paths in session field validation

Extends the CWE-22 path traversal guard to cover Windows absolute paths
of the form C:/... and D:\... — previously only leading / and \ were
checked, which missed drive-letter prefixes. Replaces the inline
startswith check with a compiled module-level regex (_TRAVERSAL_RE) that
covers all three attack patterns: .., leading /\, and leading X: drives.
Adds two regression tests for C:/windows/system32 and D:\\path\\to\\file.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
OrbisAI Security 2026-06-05 13:40:50 +05:30 committed by Teknium
parent 3a6a43cb81
commit aa2aac68b0
2 changed files with 17 additions and 1 deletions

View file

@ -12,6 +12,7 @@ import hashlib
import logging
import os
import json
import re
import threading
import uuid
from pathlib import Path
@ -66,6 +67,11 @@ from .whatsapp_identity import (
)
from utils import atomic_replace
# Matches any value that could escape the sessions directory as a file path.
# Covers: directory traversal (..), Unix/Windows absolute paths (/ \),
# and Windows drive-letter paths (C:/ D:\\ etc.).
_TRAVERSAL_RE = re.compile(r'\.\.|^[/\\]|^[A-Za-z]:')
@dataclass
class SessionSource:
@ -578,7 +584,7 @@ class SessionEntry:
# Validate path-sensitive fields to prevent directory traversal (CWE-22)
for _field, _val in (("session_key", session_key), ("session_id", session_id)):
if _val and (".." in str(_val) or str(_val).startswith(("/", "\\"))):
if _val and _TRAVERSAL_RE.search(str(_val)):
raise ValueError(
f"Invalid {_field}: potential directory traversal detected"
)

View file

@ -1085,6 +1085,16 @@ class TestSessionEntryFromDictTraversalValidation:
with pytest.raises(ValueError, match="session_id"):
SessionEntry.from_dict(self._entry(session_id="\\windows\\system32\\config"))
def test_session_id_windows_drive_letter_raises(self):
from gateway.session import SessionEntry
with pytest.raises(ValueError, match="session_id"):
SessionEntry.from_dict(self._entry(session_id="C:/windows/system32"))
def test_session_id_windows_drive_backslash_raises(self):
from gateway.session import SessionEntry
with pytest.raises(ValueError, match="session_id"):
SessionEntry.from_dict(self._entry(session_id="D:\\path\\to\\file"))
class TestEnsureLoadedSkipsInvalidEntries:
"""Regression: one bad sessions.json entry must not block valid entries from loading."""