agentscope-ai / agentscope-ai/agentscope

[Bug]: LocalWorkspaceManager reuses workdirs across users of a shared agent

Aberta
#2,107 1 comentário 0 reações 0 responsáveis Ver no GitHub
Linguagem predominante
Python
Estrelas
31.6k
Forks
3.5k
Merge médio
1d 16h
PRs com merge (30d)
103

Descrição

## Prerequisites

- [x] I searched existing issues, discussions, and pull requests.
- [x] This is a reproducible bug, not a usage question.

## Background / Description

Issue #2042 defines `user_id` as the top-level workspace isolation boundary when an agent is shared. `LocalWorkspaceManager` does not currently enforce that boundary in either its in-memory cache or its filesystem layout.

The manager accepts `user_id`, but:

1. its cache is keyed only by `workspace_id`;
2. its workdir is always `/`;
3. its `workspace_id=None` fallback calls `assign_workspace_id` with empty user and session values.

When two users create sessions for the same shared agent, the service may persist distinct logical workspace IDs while both `LocalWorkspace` instances still point to the same physical directory. If two users provide the same explicit workspace ID, they can also receive the same cached workspace object.

This issue is intentionally limited to unintended cache/workdir aliasing performed by `LocalWorkspaceManager`. It does not claim that host-local tools provide an OS-level sandbox.

## Observed Behavior

For a shared `agent_id`:

```text
owner workspace_id != viewer workspace_id
owner workdir == viewer workdir == /
```

This lets one user's normal workspace initialization reuse files persisted by another user, including MCP configuration, skills, memory, session artifacts, and tool output.

## Steps to Reproduce

```python
import asyncio
import tempfile

from agentscope.app.workspace_manager import LocalWorkspaceManager

async def main() -> None:
with tempfile.TemporaryDirectory() as basedir:
manager = LocalWorkspaceManager(basedir)

owner = await manager.get_workspace(
"owner",
"shared-agent",
"owner-session",
"owner-workspace",
)
viewer = await manager.get_workspace(
"viewer",
"shared-agent",
"viewer-session",
"viewer-workspace",
)

print(owner.workspace_id != viewer.workspace_id)
print(owner.workdir)
print(viewer.workdir)
print(owner.workdir == viewer.workdir)

asyncio.run(main())
```

Current output:

```text
True
/shared-agent
/shared-agent
True
```

A second variant using the same explicit `workspace_id` for both users returns the same cached object because the cache key has no user scope.

## Expected Behavior

- Different users must never receive the same cached local workspace solely because their workspace IDs collide.
- Different users must never be mapped to the same local workdir solely because they use the same shared agent.
- Same-user team agents must remain able to intentionally share an explicit workspace ID.
- Identifier values must not be used as unsafe path components.

## Proposed Fix

- Key the local cache by `(user_id, workspace_id)`.
- Derive the persistent workdir from filesystem-safe hashes of both `user_id` and `workspace_id`.
- Pass the real user, agent, and session values into `assign_workspace_id`.
- Route the deprecated `create_workspace` API through the same isolated path.
- Adapt TTL eviction and `close(workspace_id)` to the scoped cache keys.
- Add focused regression coverage for implicit IDs, explicit ID collisions, same-user team sharing, path traversal, TTL eviction, and lifecycle compatibility.

**Implementation status:** A mature and locally validated implementation is now available in [PR #2108](https://github.com/agentscope-ai/agentscope/pull/2108). The PR implements the complete scoped solution above and includes focused manager regression tests, existing LocalWorkspace regression coverage, pre-commit validation, and a real LocalWorkspace isolation reproduction.

## Migration Note

Legacy `/` directories do not contain owner metadata. They should not be adopted automatically because assigning such a directory to the first requesting user could expose another user's data. Any migration requires an explicit administrator-provided ownership mapping.

## Out of Scope

`LocalWorkspace` runs tools on the host and is not an OS security boundary for mutually untrusted tenants. Hard isolation for arbitrary Bash/Read access should use Docker, K8s, E2B, OpenSandbox, or another sandbox backend.

## Environment

- AgentScope: 2.0.4.post1
- Python: 3.11+
- Affected component: `LocalWorkspaceManager`
- Reproduced on Windows; the path construction is platform-independent

Guia de contribuição

Abrir o guia de contribuição

Direção de pesquisa

Start in `agentscope.app.workspace_manager` where `LocalWorkspaceManager` is defined and inspect `get_workspace`, caching, `assign_workspace_id`, `close(workspace_id)`, and `create_workspace`. Reproduce first with the provided async snippet to confirm cross-user workdir and cache collisions for `basedir/`. Then verify behavior changes with manager regression tests (implicit IDs, explicit collisions, TTL eviction, same-user sharing) so completion is distinct user-scoped cache keys and workdirs without cross-user reuse.

Escrita pelo modelo de indexação a partir do texto da issue.

Avaliação

Stack de tecnologia
python
Domínio
backend
Tipo de issue
Bug
Dificuldade
3/5
Tempo estimado
1-2 dias
Status de atividade
Estagnada
Clareza
Claramente especificada
Facilidade para iniciantes
34/100

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.