home-assistant/core · error · InvalidBackupFilename
Invalid filename: {suggested_filename}
Error message
Invalid filename: {suggested_filename} What it means
Raised by BackupManager._async_receive_backup while validating the uploaded multipart file's filename. suggested_filename defaults to 'backup.tar' when absent; it is sanitized through PureWindowsPath(...).name and rejected if that is empty, differs from the original (meaning it contained path separators like '/' or '\\' or a drive component), or equals '..'. This blocks path-traversal via the upload filename.
Source
Thrown at homeassistant/components/backup/manager.py:1015
finally:
self.async_on_backup_event(IdleEvent())
async def _async_receive_backup(
self,
*,
agent_ids: list[str],
contents: aiohttp.BodyPartReader,
) -> str:
"""Receive and store a backup file from upload."""
contents.chunk_size = BUF_SIZE
suggested_filename = contents.filename or "backup.tar"
safe_filename = PureWindowsPath(suggested_filename).name
if (
not safe_filename
or safe_filename != suggested_filename
or safe_filename == ".."
):
raise InvalidBackupFilename(f"Invalid filename: {suggested_filename}")
self.async_on_backup_event(
ReceiveBackupEvent(
reason=None,
stage=ReceiveBackupStage.RECEIVE_FILE,
state=ReceiveBackupState.IN_PROGRESS,
)
)
written_backup = await self._reader_writer.async_receive_backup(
agent_ids=agent_ids,
stream=contents,
suggested_filename=suggested_filename,
)
self.async_on_backup_event(
ReceiveBackupEvent(
reason=None,
stage=ReceiveBackupStage.UPLOAD_TO_AGENTS,
state=ReceiveBackupState.IN_PROGRESS,
)View on GitHub (pinned to 58a3fdb3ea)
Solutions
- Send a plain base filename in the multipart Content-Disposition: filename="backup.tar" with no directories or drive letters.
- In client code, use Path(filepath).name (or basename) when constructing the multipart field from a full path.
- Retry the upload with the corrected filename; nothing else about the request needs to change.
Example fix
# before (python client)
files = {"file": (str(full_path), fh)} # sends '/home/user/backups/x.tar'
# after
from pathlib import Path
files = {"file": (Path(full_path).name, fh)} # sends 'x.tar' Defensive patterns
Strategy: validation
Validate before calling
from pathlib import PurePath
def valid_upload_filename(name: str | None) -> bool:
if name is None:
return True # defaults to backup.tar
return bool(name) and PurePath(name).name == name and name not in ("..", ".") Try / catch
from homeassistant.components.backup.manager import InvalidBackupFilename
try:
backup_id = await manager.async_receive_backup(
agent_ids=agent_ids, contents=contents
)
except InvalidBackupFilename as err:
return web.Response(status=400, text=str(err)) Prevention
- Always send Path(full_path).name as the multipart filename.
- Reject/normalize filenames containing '/', '\\' or '..' client-side.
- Default to a plain 'backup.tar' name when the source name is untrusted.
When it happens
Trigger: POSTing a multipart upload whose filename field contains 'sub/dir/backup.tar', '..\\..\\evil.tar', 'C:\\backup.tar', is empty-but-not-None, or resolves to '..' after PureWindowsPath normalization.
Common situations: Custom API clients sending full paths as filename; curl/scripts reusing a file path string as filename; deliberately malicious requests probing the upload endpoint.
Related errors
- Refusing to write outside {self._backup_dir}: {candidate}
- Failed to upload backup
- Upload timed out after {UPLOAD_TIMEOUT} seconds
- {result}
- Backup manager busy: {self.state}
AI-assisted analysis of home-assistant/core@58a3fdb3ea (2026-08-14).
Data as JSON: /api/errors/e0bb1c0529471c7e.
Report an issue: GitHub.