bytedance/deer-flow · warning · HTTPException
Invalid path
Error message
Invalid path
What it means
HTTP 400 raised by DELETE /threads/{thread_id}/uploads/{filename} when the filename triggers PathTraversalError — the path-safety layer rejects URL segments that would escape the thread's uploads directory (../, absolute paths, symlink tricks). This is a deliberate guard, not a bug.
Source
Thrown at backend/app/gateway/routers/uploads.py:478
"""List all files in a thread's uploads directory."""
try:
result = await run_file_io(_list_uploaded_files_for_thread, thread_id, get_effective_user_id())
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
return UploadListResponse(**result)
@router.delete("/{filename}")
@require_permission("threads", "delete", owner_check=True, require_existing=True)
async def delete_uploaded_file(thread_id: ThreadId, filename: str, request: Request) -> dict:
"""Delete a file from a thread's uploads directory."""
try:
return await run_file_io(_delete_uploaded_file_for_thread, thread_id, filename, get_effective_user_id())
except FileNotFoundError:
raise HTTPException(status_code=404, detail=f"File not found: {filename}")
except PathTraversalError:
raise HTTPException(status_code=400, detail="Invalid path")
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
except Exception as e:
logger.error(f"Failed to delete {filename}: {e}")
raise HTTPException(status_code=500, detail=f"Failed to delete {filename}: {str(e)}")
View on GitHub (pinned to 1dd6ba1acb)
Solutions
- Delete by the exact plain filename returned by the uploads list endpoint — no directories, no '..', no absolute paths.
- URL-encode the filename once (encodeURIComponent) when building the path.
- Strip path components client-side before constructing the request.
Example fix
// before
await fetch(`/api/threads/${tid}/uploads/${file.fullPath}`);
// after
const name = file.fullPath.split('/').pop();
await fetch(`/api/threads/${tid}/uploads/${encodeURIComponent(name)}`); Defensive patterns
Strategy: validation
Validate before calling
function isSafeFilename(name) {
return typeof name === 'string'
&& !name.includes('/')
&& !name.includes('\\')
&& name !== '.' && name !== '..'
&& !name.startsWith('.');
}
if (!isSafeFilename(filename)) throw new Error('Invalid filename'); Type guard
const isSafeFilename = (n: unknown): n is string =>
typeof n === 'string' && /^[-. A-Za-z0-9_()]+$/.test(n) && n !== '.' && n !== '..' && !n.includes('/'); Prevention
- Send only the basename (last path segment) of any filename.
- encodeURIComponent the filename exactly once when building URLs.
- Reject client-side any input containing '..', separators, or leading slashes.
When it happens
Trigger: Passing a filename containing '..' segments, a leading slash, or encoded traversal sequences (e.g. %2e%2e%2f) in the DELETE path.
Common situations: Client concatenating unvalidated user input into the URL; penetration tests / scanners probing the endpoint; mis-encoded filenames from scripts.
Related errors
- {e}
- MCP server '{server_name}' command must be a single executab
- MCP server '{name}' uses disallowed stdio command '{command_
- MCP server '{name}' passes '{exec_flag}' to '{command_name}'
- MCP server '{name}' sets environment variable '{env_name}',
AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14).
Data as JSON: /api/errors/adcfc0bba1236c70.
Report an issue: GitHub.