T05 · Unauthorized Access and Privilege Escalation
Error
- Location
- references/INSTALL.md:56
- Finding
- Caller-Controlled Agent ID Enables Path Traversal Outside the Agent Directory<![CDATA[ ## Vulnerability Details **File Location**: `references/INSTALL.md:56-60`; `references/backend-protocol-schemas.ts.txt:14-59`; `references/backend-rpc-handlers.ts.txt:90-96, 119-128, 162-168, 184-190`; `references/backend-history-migration.ts.txt:29-40, 68-114, 197-204` **Vulnerability Type**: Path traversal and insufficient authorization validation **Risk Level**: High ### Complete Code Snippet The documented path helper places an unvalidated agent identifier directly into a filesystem path: ```ts export function resolveSessionTranscriptsDirForAgent(agentId?: string): string { const home = process.env.OPENCLAW_HOME || path.join(os.homedir(), ".openclaw"); const id = agentId || "main"; return path.join(home, "agents", id, "sessions"); } ``` The RPC schemas only require a non-empty string: ```ts export const SessionsArchivedParamsSchema = Type.Object( { agentId: Type.Optional(NonEmptyString), limit: Type.Optional(Type.Integer({ minimum: 1, maximum: 200 })), offset: Type.Optional(Type.Integer({ minimum: 0 })), search: Type.Optional(Type.String()), status: Type.Optional(Type.Union([Type.Literal("active"), Type.Literal("archived")])), }, { additionalProperties: false }, ); export const SessionsResumeParamsSchema = Type.Object( { sessionId: NonEmptyString, agentId: Type.Optional(NonEmptyString), }, { additionalProperties: false }, ); export const SessionsRenameParamsSchema = Type.Object( { sessionId: NonEmptyString, displayName: Type.String(), agentId: Type.Optional(NonEmptyString), }, { additionalProperties: false }, ); export const SessionsDeleteArchivedParamsSchema = Type.Object( { sessionId: NonEmptyString, agentId: Type.Optional(NonEmptyString), deleteTranscript: Type.Optional(Type.Boolean()), }, { additionalProperties: false }, ); ``` The supplied value is used without checking that it identifies a configured agent or remains beneath the expected directory: ``` ...[truncated 3935 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Do not derive filesystem paths directly from an RPC-provided agent identifier. 2. Resolve the identifier against a trusted list of configured agents and reject unknown IDs. 3. Restrict agent identifiers to a conservative allowlist, such as letters, numbers, underscores, and hyphens. 4. Explicitly reject `/`, `\`, `.`, `..`, absolute paths, null bytes, and platform-specific path separators. 5. Canonicalize and verify containment before any filesystem access: ```ts const agentsRoot = path.resolve(home, "agents"); const candidate = path.resolve(agentsRoot, validatedAgentId, "sessions"); const relative = path.relative(agentsRoot, candidate); if ( relative === "" || relative.startsWith("..") || path.isAbsolute(relative) ) { throw new Error("Invalid agent directory"); } ``` 6. Enforce per-agent authorization in every affected RPC handler. 7. Run migration only for directories derived from trusted server-side configuration. 8. Add tests covering `../`, absolute paths, backslash traversal, encoded separators, unknown agents, and cross-agent requests. ]]>
