What happened?
The desktop source deletion path accepts a caller-provided sourceSlug and uses it as a filesystem path segment when constructing the deletion target.
A crafted slug containing path traversal segments can make the resolved delete target escape the intended workspace sources directory. For example:
sourceSlug = "../sessions"
sourceRoot = join(workspaceRoot, "sources")
deleteTarget = join(sourceRoot, sourceSlug)
= join(workspaceRoot, "sources", "../sessions")
= [workspace]\sessions
Because path.join() normalizes .. segments, sources/../sessions resolves to the neighboring sessions directory. If that directory exists, the previous delete path can recursively remove it.
This is a CWE-22 style path traversal issue: external input is used to construct a path intended to remain under a restricted directory, but special path elements are not constrained before path resolution.
Steps to reproduce
In an authorized source deletion context for a workspace:
- Create a temporary workspace with both directories:
sources/good-source/
sessions/session-1/marker.txt
- Attempt to delete a source with a path-like slug:
- Observe the resolved deletion target.
Expected behavior
sourceSlug should be treated as a source identifier, not as an arbitrary filesystem path segment. Path-like slugs such as ../sessions and ..\sessions should be rejected before any recursive filesystem deletion is attempted.
Actual behavior
A local isolated reproduction showed that ../sessions resolves to the neighboring sessions directory and can be recursively deleted.
sourceSlug=../sessions
resolvedTarget=[workspace]\sessions
beforeSessionsExists=true
afterSessionsExists=false
Impact and scope
The impact is limited to callers that can invoke source deletion for a workspace. A path-like sourceSlug can redirect the recursive delete target from sources/ to a neighboring workspace directory such as sessions.
This issue does not claim arbitrary filesystem deletion, privilege escalation, or unauthenticated remote access.
Suggested fix
Validate sourceSlug before resolving the delete target. Normal generated source slugs are lowercase alphanumeric names with hyphens, such as good-source, so path-like values can be rejected early.
Related PR
A proposed fix is available in #5829.
What happened?
The desktop source deletion path accepts a caller-provided
sourceSlugand uses it as a filesystem path segment when constructing the deletion target.A crafted slug containing path traversal segments can make the resolved delete target escape the intended workspace
sourcesdirectory. For example:Because
path.join()normalizes..segments,sources/../sessionsresolves to the neighboringsessionsdirectory. If that directory exists, the previous delete path can recursively remove it.This is a CWE-22 style path traversal issue: external input is used to construct a path intended to remain under a restricted directory, but special path elements are not constrained before path resolution.
Steps to reproduce
In an authorized source deletion context for a workspace:
Expected behavior
sourceSlugshould be treated as a source identifier, not as an arbitrary filesystem path segment. Path-like slugs such as../sessionsand..\sessionsshould be rejected before any recursive filesystem deletion is attempted.Actual behavior
A local isolated reproduction showed that
../sessionsresolves to the neighboringsessionsdirectory and can be recursively deleted.Impact and scope
The impact is limited to callers that can invoke source deletion for a workspace. A path-like
sourceSlugcan redirect the recursive delete target fromsources/to a neighboring workspace directory such assessions.This issue does not claim arbitrary filesystem deletion, privilege escalation, or unauthenticated remote access.
Suggested fix
Validate
sourceSlugbefore resolving the delete target. Normal generated source slugs are lowercase alphanumeric names with hyphens, such asgood-source, so path-like values can be rejected early.Related PR
A proposed fix is available in #5829.