{"record":{"id":"5b5ff4f2d603db69","repo":"HKUDS/DeepTutor","slug":"invalid-folder-path","errorCode":null,"errorMessage":"Invalid folder path","messagePattern":"Invalid folder path","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"deeptutor/api/routers/knowledge.py","lineNumber":332,"sourceCode":"    cleaned = _BAD_PATH_CHARS.sub(\"\", segment).strip().strip(\".\")\n    return cleaned[:128]\n\n\ndef _sanitize_rel_subdir(rel_path: str | None) -> str:\n    \"\"\"Return a safe POSIX relative subdir (folders only, no traversal).\n\n    A leading/trailing or interior ``..``/absolute marker raises 400 so a\n    crafted directory upload can never escape ``raw/``.\n    \"\"\"\n    if not rel_path:\n        return \"\"\n    parts: list[str] = []\n    for raw_seg in str(rel_path).replace(\"\\\\\", \"/\").split(\"/\"):\n        seg = raw_seg.strip()\n        if seg in (\"\", \".\"):\n            continue\n        if seg == \"..\":\n            raise HTTPException(status_code=400, detail=\"Invalid folder path\")\n        safe = _sanitize_path_segment(seg)\n        if safe:\n            parts.append(safe)\n    return \"/\".join(parts)\n\n\ndef _safe_join_raw(raw_dir: Path, rel_path: str) -> Path:\n    \"\"\"Resolve ``rel_path`` under ``raw_dir``, rejecting traversal.\"\"\"\n    target = (raw_dir / rel_path).resolve()\n    try:\n        target.relative_to(raw_dir.resolve())\n    except ValueError as exc:\n        raise HTTPException(status_code=403, detail=\"Access denied\") from exc\n    return target\n\n\ndef _save_uploaded_files(\n    files: list[UploadFile],","sourceCodeStart":314,"sourceCodeEnd":350,"githubUrl":"https://github.com/HKUDS/DeepTutor/blob/3e82f130422a813cdd73c10b21a44e9325f5821a/deeptutor/api/routers/knowledge.py#L314-L350","documentation":"Raised by _sanitize_rel_subdir when a segment of a user-supplied relative folder path equals '..' after normalizing backslashes and stripping whitespace. This is the path-traversal guard that stops writes outside the knowledge base's raw directory.","triggerScenarios":"Calling folder creation, file move, or upload endpoints with rel_paths/subdir like '../escape', 'a/../../b', or '..\\\\..\\\\x'; also '..' hidden behind whitespace (' .. ') since segments are stripped.","commonSituations":"Frontends passing user-typed folder paths verbatim; clients constructing paths from joined user input; attempts (accidental or malicious) to write outside the KB root.","solutions":["Reject or strip '..' segments client-side before calling the API","Always build rel paths from sanitized folder names, never from raw OS paths","URL-encode the whole path as a single folder label instead of composing traversal-style paths"],"exampleFix":"# before\nrel_path = '../../etc'\n# after\nrel_path = 'notes/lecture1'","handlingStrategy":"validation","validationCode":"def safe_rel_path(p):\n    parts = [s.strip() for s in str(p).replace('\\\\','/').split('/')]\n    assert '..' not in parts, 'traversal segment'\n    return '/'.join(s for s in parts if s not in ('','.'))","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never compose rel paths from raw user text","Strip '..' segments client-side","Use single-label folder names where possible"],"tags":["path-traversal","security","validation","http-400"],"backgroundTag":"path-traversal-blocked","analyzedSha":"3e82f130422a813cdd73c10b21a44e9325f5821a","analyzedAt":"2026-08-27T06:57:25.364Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}