agentscope-ai / agentscope-ai/agentscope

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

Ouverte
#2,107 1 commentaire 0 réactions 0 personnes assignées Voir sur GitHub
Langage dominant
Python
Étoiles
31.5k
Forks
3.5k
Merge moyen
1 j 23 h
PR mergées (30 j)
95

Description

## 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

Guide de contribution

Ouvrir le guide de contribution

Évaluation

Cette issue n'a pas encore été évaluée.

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.