{"record":{"id":"ec20cdeb16f321a1","repo":"agentscope-ai/agentscope","slug":"invalid-blob-key-key-r","errorCode":null,"errorMessage":"Invalid blob key: {key!r}","messagePattern":"Invalid blob key: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/agentscope/app/rag/blob_store/_local.py","lineNumber":69,"sourceCode":"\n    def _path_for(self, key: str) -> Path:\n        \"\"\"Resolve a backend-relative key to an absolute filesystem path.\n\n        Rejects keys that try to escape :attr:`_root` via ``..`` or\n        absolute paths.  Callers pick keys server-side so this is\n        defensive rather than a primary trust boundary, but we still\n        refuse to write outside the root.\n\n        Args:\n            key (`str`):\n                Backend-relative key.\n\n        Returns:\n            `Path`:\n                The absolute filesystem path within :attr:`_root`.\n        \"\"\"\n        if not key or key.startswith(\"/\") or \"..\" in Path(key).parts:\n            raise ValueError(f\"Invalid blob key: {key!r}\")\n        path = (self._root / key).resolve()\n        if self._root not in path.parents and path != self._root:\n            raise ValueError(f\"Blob key {key!r} escapes the root directory.\")\n        return path\n\n    def _key_from_uri(self, uri: str) -> str:\n        \"\"\"Extract the backend-relative key from a ``local://`` URI.\"\"\"\n        if not uri.startswith(_SCHEME):\n            raise ValueError(f\"Not a local blob URI: {uri!r}\")\n        return uri[len(_SCHEME) :]\n\n    async def write_stream(self, key: str, stream: IO[bytes]) -> str:\n        \"\"\"Copy ``stream`` into the blob at ``key`` in 1 MiB chunks.\n\n        Creates intermediate directories as needed.  Existing blobs at\n        the same key are overwritten — keys are generated server-side\n        from document ids, so collisions only happen on intentional\n        re-uploads.","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/agentscope-ai/agentscope/blob/e90f1c7592896cc95f6e5ee506194f533378247d/src/agentscope/app/rag/blob_store/_local.py#L51-L87","documentation":"LocalBlobStore._path_for validates every blob key before mapping it to a filesystem path under the store's root. It raises ValueError('Invalid blob key: ...') when the key is empty, starts with '/' (absolute path), or contains a '..' path component. This is a path-traversal guard shared by write_stream, open, size, delete, and exists.","triggerScenarios":"Calling any LocalBlobStore blob method with key='' , key='/abs/path', or key='a/../../etc/passwd'. Windows-style components or URLs (e.g. 'local://foo') passed as keys also fail the checks.","commonSituations":"Passing a full local:// URI where a bare key is expected; constructing keys from unvalidated user input; joining paths with a leading slash; sending filenames containing '..' from an upload form.","solutions":["Pass a relative key like 'kb123/chunk.bin', never a URI or absolute path","Strip the scheme first: use the store's _key_from_uri helper or uri.removeprefix('local://') if you hold a URI","Validate/sanitize user-supplied keys: reject empty, absolute, and '..'-containing segments before calling the store","Normalize with PurePosixPath(key).parts to inspect segments"],"exampleFix":"# before\nawait store.write_stream('/data/abc.bin', stream)  # ValueError: Invalid blob key\n\n# after\nawait store.write_stream('data/abc.bin', stream)","handlingStrategy":"validation","validationCode":"from pathlib import PurePosixPath\n\ndef valid_blob_key(key: str) -> bool:\n    if not key or key.startswith('/'):\n        return False\n    return '..' not in PurePosixPath(key).parts\n\nassert valid_blob_key(key), f'bad blob key {key!r}'","typeGuard":"from pathlib import PurePosixPath\n\ndef is_valid_blob_key(key: str) -> bool:\n    return bool(key) and not key.startswith('/') and '..' not in PurePosixPath(key).parts","tryCatchPattern":"try:\n    await store.write_stream(key, stream)\nexcept ValueError as e:\n    if 'Invalid blob key' in str(e):\n        ...  # sanitize key and retry\n    raise","preventionTips":["Always pass relative POSIX keys ('kb/blob.bin'), never URIs or absolute paths","Map user-supplied filenames to opaque ids (uuid/hash) before using as keys","Strip 'local://' before passing a URI-derived string as a key"],"tags":["blob-store","path-traversal","validation","local-storage"],"backgroundTag":"invalid-path-argument","analyzedSha":"e90f1c7592896cc95f6e5ee506194f533378247d","analyzedAt":"2026-08-28T18:24:12.087Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}