# Understanding Symphony's Path Safety System: Secure Workspace Isolation in OpenAI Symphony

> Discover Symphony's path safety system. It stops directory traversal by validating workspace paths stay within boundaries before filesystem operations. Learn more about secure isolation.

- Repository: [OpenAI/symphony](https://github.com/openai/symphony)
- Tags: deep-dive
- Published: 2026-05-08

---

**Symphony's path safety system prevents directory traversal attacks by canonicalizing all workspace paths and validating they remain within configured root boundaries before any filesystem operations occur.**

Symphony isolates each Codex job in a dedicated workspace on the host machine to prevent filesystem escape vulnerabilities. The path safety system, centered around the `SymphonyElixir.PathSafety` module, ensures that malicious symlinks or path traversal sequences cannot breach the workspace root directory. This mechanism is enforced across local operations and remote SSH executions, providing a unified security boundary for all workspace-related activities.

## Core Mechanisms of the Path Safety System

### Path Canonicalization

At the heart of the system lies the `SymphonyElixir.PathSafety.canonicalize/1` function, implemented in [`elixir/lib/symphony_elixir/path_safety.ex`](https://github.com/openai/symphony/blob/main/elixir/lib/symphony_elixir/path_safety.ex) (lines 4-16). This function resolves relative components (`..`, `.`) and symbolic links to determine the real filesystem location of any requested path.

The implementation expands the input path, splits it into a root and segments, then recursively resolves each segment. Symlinks are safely read via `:file.read_link_all/1` and re-expanded relative to their containing directory. This process ensures that subsequent safety checks operate on absolute, fully-resolved paths rather than potentially malicious user input.

### Workspace Validation

After canonicalization, `Workspace.validate_workspace_path/2` (defined in [`elixir/lib/symphony_elixir/workspace.ex`](https://github.com/openai/symphony/blob/main/elixir/lib/symphony_elixir/workspace.ex) at lines 58-80) enforces the critical security constraints:

- The workspace path must not resolve to the root directory itself (workspace ≠ root)
- The workspace must start with the canonical root prefix
- If the expanded path (pre-canonicalization) attempts to escape via a symlink, it is immediately rejected

Only paths satisfying all three conditions pass validation. When validation fails, the function returns detailed error tuples such as `{:workspace_outside_root, bad_path, root}`, which callers propagate as `{:error, ...}` values.

## Remote Host Security

The path safety system extends to remote SSH environments through local pre-validation. When creating workspaces on remote hosts via `Workspace.create_for_issue/2` or executing remote commands through `Workspace.run_remote_command/3`, Symphony applies `PathSafety.canonicalize/1` on the local side first.

The remote host receives only the prepared absolute path, ensuring that path-traversal vulnerabilities cannot be introduced by compromised remote scripts or malicious SSH targets. This architecture guarantees that the security boundary is enforced before any network transmission occurs.

## Integration Across the Codebase

The path safety system serves as a single source of truth for workspace path handling. According to the OpenAI Symphony source code, multiple modules invoke `PathSafety.canonicalize/1`, ensuring that any future security enhancements propagate automatically:

- **[`elixir/lib/symphony_elixir/workspace.ex`](https://github.com/openai/symphony/blob/main/elixir/lib/symphony_elixir/workspace.ex)**: Creates, validates, and removes per-issue workspaces
- **[`elixir/lib/symphony_elixir/config/schema.ex`](https://github.com/openai/symphony/blob/main/elixir/lib/symphony_elixir/config/schema.ex)**: Validates configuration values and canonicalizes the workspace root
- **[`elixir/lib/symphony_elixir/codex/app_server.ex`](https://github.com/openai/symphony/blob/main/elixir/lib/symphony_elixir/codex/app_server.ex)**: Server entry point for Codex agents; uses path safety when preparing remote workspaces

## Practical Code Examples

The following examples demonstrate safe workspace creation and direct path canonicalization usage:

```elixir

# Example: safely create a workspace for a GitHub issue

{:ok, workspace_path} = SymphonyElixir.Workspace.create_for_issue(%{
  id: 123,
  identifier: "openai/symphony#123"
})

# Internally:

#   1️⃣ safe_identifier/1 sanitises the identifier → "openai_symphony_123"

#   2️⃣ workspace_path_for_issue/2 builds "<root>/openai_symphony_123"

#   3️⃣ PathSafety.canonicalize/1 resolves the absolute, symlink‑free path

#   4️⃣ validate_workspace_path/2 ensures it stays inside the root

```

```elixir

# Direct use of the Path‑Safety module – useful for custom tooling

case SymphonyElixir.PathSafety.canonicalize("/tmp/../var/app/../sym_workspace") do
  {:ok, safe_path} ->
    IO.puts("Canonical path: #{safe_path}")

  {:error, {:path_canonicalize_failed, original, reason}} ->
    IO.warn("Failed to canonicalise #{original}: #{inspect(reason)}")
end

```

```elixir

# Handling an error when a workspace tries to escape the root

{:error, {:workspace_outside_root, bad_path, root}} =
  SymphonyElixir.Workspace.validate_workspace_path("/tmp/evil", nil)

IO.puts("Workspace #{bad_path} is outside the configured root #{root}")

```

## Summary

- **Canonicalization first**: All paths are processed through `PathSafety.canonicalize/1` in [`elixir/lib/symphony_elixir/path_safety.ex`](https://github.com/openai/symphony/blob/main/elixir/lib/symphony_elixir/path_safety.ex) to resolve symlinks and relative segments before validation.
- **Root containment**: `Workspace.validate_workspace_path/2` enforces that workspaces remain strictly within the configured root directory and never resolve to the root itself.
- **Remote pre-validation**: Security checks execute locally before transmitting paths to remote SSH hosts, preventing traversal attacks in distributed environments.
- **Unified enforcement**: The system provides a single source of truth used by `Workspace`, `Config.Schema`, and `Codex.AppServer` modules.
- **Fail-safe errors**: Violations return detailed error tuples (e.g., `{:workspace_outside_root, ...}`) rather than allowing unsafe filesystem access.

## Frequently Asked Questions

### How does Symphony prevent symlink-based directory traversal attacks?

Symphony's path safety system prevents symlink attacks by fully resolving all symbolic links during the canonicalization phase. The `PathSafety.canonicalize/1` function uses `:file.read_link_all/1` to read link targets and re-expands them relative to their containing directory, ensuring the final absolute path is known before any safety checks compare it against the allowed root boundary.

### What happens when a workspace path fails validation?

When `Workspace.validate_workspace_path/2` detects a path outside the root directory or resolving to the root itself, it returns an error tuple such as `{:workspace_outside_root, requested_path, root_path}`. This error propagates through the call stack as `{:error, reason}`, preventing any filesystem creation, removal, or remote command execution from proceeding with the unsafe path.

### Does the path safety system protect remote SSH workspaces?

Yes, the path safety system protects remote workspaces by performing all canonicalization and validation steps locally before any remote communication occurs. Functions like `Workspace.create_for_issue/2` prepare the absolute path locally using `PathSafety.canonicalize/1`, then transmit only the validated path to the remote host. This ensures that compromised remote environments cannot influence the path resolution process or introduce traversal sequences.

### Which modules depend on the PathSafety canonicalization function?

According to the OpenAI Symphony source code, `PathSafety.canonicalize/1` serves as the single source of truth for multiple critical modules: `SymphonyElixir.Workspace` handles workspace lifecycle management, `SymphonyElixir.Config.Schema` validates configuration roots, and `SymphonyElixir.Codex.AppServer` prepares paths for Codex agent environments. This centralized design ensures consistent security enforcement across the entire application.