@@ -11,6 +11,7 @@ import (
1111 "net/http"
1212 "net/url"
1313 "os"
14+ "path"
1415 "sort"
1516 "strings"
1617 "time"
@@ -2512,25 +2513,37 @@ func PutSessionWorkspaceFile(c *gin.Context) {
25122513 c .JSON (http .StatusBadRequest , gin.H {"error" : "Project namespace required" })
25132514 return
25142515 }
2515- sub := strings .TrimPrefix (c .Param ("path" ), "/" )
2516- absPath := "/sessions/" + session + "/workspace/" + sub
2517- token := c .GetHeader ("Authorization" )
2518- if strings .TrimSpace (token ) == "" {
2519- token = c .GetHeader ("X-Forwarded-Access-Token" )
2520- }
25212516
2522- // Try temp service first (for completed sessions), then regular service
2523- serviceName := fmt .Sprintf ("temp-content-%s" , session )
2517+ // Get user-scoped K8s clients and validate authentication IMMEDIATELY
25242518 reqK8s , reqDyn := GetK8sClientsForRequest (c )
2525- serviceFound := false
2526-
2527- // Check if user has valid auth before checking services or spawning temp pods
2528- // This prevents unauthenticated requests from triggering resource creation
25292519 if reqK8s == nil || reqDyn == nil {
25302520 c .JSON (http .StatusUnauthorized , gin.H {"error" : "Invalid or missing authentication token" })
25312521 return
25322522 }
25332523
2524+ // Validate and sanitize path to prevent directory traversal
2525+ sub := strings .TrimPrefix (c .Param ("path" ), "/" )
2526+ // Check for path traversal attempts
2527+ if strings .Contains (sub , ".." ) {
2528+ log .Printf ("PutSessionWorkspaceFile: path traversal attempt detected: %s" , sub )
2529+ c .JSON (http .StatusBadRequest , gin.H {"error" : "Invalid path: path traversal not allowed" })
2530+ return
2531+ }
2532+ // Construct absolute path - Clean removes any remaining traversal attempts
2533+ workspaceBase := "/sessions/" + session + "/workspace/"
2534+ absPath := path .Clean (workspaceBase + sub )
2535+ // Verify path stays within workspace directory
2536+ if ! strings .HasPrefix (absPath , workspaceBase ) {
2537+ log .Printf ("PutSessionWorkspaceFile: path escapes workspace: %s" , absPath )
2538+ c .JSON (http .StatusBadRequest , gin.H {"error" : "Invalid path: must be within workspace directory" })
2539+ return
2540+ }
2541+
2542+ token := c .GetHeader ("Authorization" )
2543+ if strings .TrimSpace (token ) == "" {
2544+ token = c .GetHeader ("X-Forwarded-Access-Token" )
2545+ }
2546+
25342547 // RBAC check: verify user has update permission on agenticsessions (file operations modify session state)
25352548 ssar := & authzv1.SelfSubjectAccessReview {
25362549 Spec : authzv1.SelfSubjectAccessReviewSpec {
@@ -2553,7 +2566,10 @@ func PutSessionWorkspaceFile(c *gin.Context) {
25532566 return
25542567 }
25552568
2556- // reqK8s and reqDyn are guaranteed non-nil after auth check above
2569+ // Try temp service first (for completed sessions), then regular service
2570+ serviceName := fmt .Sprintf ("temp-content-%s" , session )
2571+ serviceFound := false
2572+
25572573 if _ , err := reqK8s .CoreV1 ().Services (project ).Get (c .Request .Context (), serviceName , v1.GetOptions {}); err != nil {
25582574 // Temp service doesn't exist, try regular service
25592575 serviceName = fmt .Sprintf ("ambient-content-%s" , session )
@@ -2683,25 +2699,37 @@ func DeleteSessionWorkspaceFile(c *gin.Context) {
26832699 c .JSON (http .StatusBadRequest , gin.H {"error" : "Project namespace required" })
26842700 return
26852701 }
2686- sub := strings .TrimPrefix (c .Param ("path" ), "/" )
2687- absPath := "/sessions/" + session + "/workspace/" + sub
2688- token := c .GetHeader ("Authorization" )
2689- if strings .TrimSpace (token ) == "" {
2690- token = c .GetHeader ("X-Forwarded-Access-Token" )
2691- }
26922702
2693- // Try temp service first, then regular service
2694- serviceName := fmt .Sprintf ("temp-content-%s" , session )
2703+ // Get user-scoped K8s clients and validate authentication IMMEDIATELY
26952704 reqK8s , reqDyn := GetK8sClientsForRequest (c )
2696- serviceFound := false
2697-
2698- // Check if user has valid auth before checking services
2699- // This prevents unauthenticated requests from accessing workspace files
27002705 if reqK8s == nil || reqDyn == nil {
27012706 c .JSON (http .StatusUnauthorized , gin.H {"error" : "Invalid or missing authentication token" })
27022707 return
27032708 }
27042709
2710+ // Validate and sanitize path to prevent directory traversal
2711+ sub := strings .TrimPrefix (c .Param ("path" ), "/" )
2712+ // Check for path traversal attempts
2713+ if strings .Contains (sub , ".." ) {
2714+ log .Printf ("DeleteSessionWorkspaceFile: path traversal attempt detected: %s" , sub )
2715+ c .JSON (http .StatusBadRequest , gin.H {"error" : "Invalid path: path traversal not allowed" })
2716+ return
2717+ }
2718+ // Construct absolute path - Clean removes any remaining traversal attempts
2719+ workspaceBase := "/sessions/" + session + "/workspace/"
2720+ absPath := path .Clean (workspaceBase + sub )
2721+ // Verify path stays within workspace directory
2722+ if ! strings .HasPrefix (absPath , workspaceBase ) {
2723+ log .Printf ("DeleteSessionWorkspaceFile: path escapes workspace: %s" , absPath )
2724+ c .JSON (http .StatusBadRequest , gin.H {"error" : "Invalid path: must be within workspace directory" })
2725+ return
2726+ }
2727+
2728+ token := c .GetHeader ("Authorization" )
2729+ if strings .TrimSpace (token ) == "" {
2730+ token = c .GetHeader ("X-Forwarded-Access-Token" )
2731+ }
2732+
27052733 // RBAC check: verify user has update permission on agenticsessions (file operations modify session state)
27062734 ssar := & authzv1.SelfSubjectAccessReview {
27072735 Spec : authzv1.SelfSubjectAccessReviewSpec {
@@ -2724,7 +2752,10 @@ func DeleteSessionWorkspaceFile(c *gin.Context) {
27242752 return
27252753 }
27262754
2727- // reqK8s is guaranteed non-nil after auth check above
2755+ // Try temp service first, then regular service
2756+ serviceName := fmt .Sprintf ("temp-content-%s" , session )
2757+ serviceFound := false
2758+
27282759 if _ , err := reqK8s .CoreV1 ().Services (project ).Get (c .Request .Context (), serviceName , v1.GetOptions {}); err != nil {
27292760 // Temp service doesn't exist, try regular service
27302761 serviceName = fmt .Sprintf ("ambient-content-%s" , session )
0 commit comments