diff --git a/cmd/fpkg/app.go b/cmd/fpkg/app.go
index cf92dad..e67ef11 100644
--- a/cmd/fpkg/app.go
+++ b/cmd/fpkg/app.go
@@ -73,6 +73,7 @@ func (app *appInfo) toFst(pathSet *appPathSet, argv []string, flagDropShell bool
 			Username: "fortify",
 			Inner:    path.Join("/data/data", app.ID),
 			Outer:    pathSet.homeDir,
+			Shell:    shellPath,
 			Sandbox: &fst.SandboxConfig{
 				Hostname:      formatHostname(app.Name),
 				Devel:         app.Devel,
diff --git a/cmd/fpkg/with.go b/cmd/fpkg/with.go
index d321de3..f9ffe84 100644
--- a/cmd/fpkg/with.go
+++ b/cmd/fpkg/with.go
@@ -34,6 +34,7 @@ func withNixDaemon(
 			Username: "fortify",
 			Inner:    path.Join("/data/data", app.ID),
 			Outer:    pathSet.homeDir,
+			Shell:    shellPath,
 			Sandbox: &fst.SandboxConfig{
 				Hostname: formatHostname(app.Name) + "-" + action,
 				Userns:   true, // nix sandbox requires userns
@@ -72,6 +73,7 @@ func withCacheDir(
 			Username: "nixos",
 			Inner:    path.Join("/data/data", app.ID, "cache"),
 			Outer:    pathSet.cacheDir, // this also ensures cacheDir via shim
+			Shell:    shellPath,
 			Sandbox: &fst.SandboxConfig{
 				Hostname: formatHostname(app.Name) + "-" + action,
 				Seccomp:  seccomp.FlagMultiarch,
diff --git a/fst/config.go b/fst/config.go
index 866f730..48f74eb 100644
--- a/fst/config.go
+++ b/fst/config.go
@@ -35,6 +35,8 @@ type ConfinementConfig struct {
 	Inner string `json:"home_inner"`
 	// home directory in init namespace
 	Outer string `json:"home"`
+	// absolute path to shell, empty for host shell
+	Shell string `json:"shell,omitempty"`
 	// abstract sandbox configuration
 	Sandbox *SandboxConfig `json:"sandbox"`
 	// extra acl ops, runs after everything else
@@ -97,6 +99,7 @@ func Template() *Config {
 			Username: "chronos",
 			Outer:    "/var/lib/persist/home/org.chromium.Chromium",
 			Inner:    "/var/lib/fortify",
+			Shell:    "/run/current-system/sw/bin/zsh",
 			Sandbox: &SandboxConfig{
 				Hostname:      "localhost",
 				Devel:         true,
diff --git a/internal/app/seal.go b/internal/app/seal.go
index 6928423..48b81e3 100644
--- a/internal/app/seal.go
+++ b/internal/app/seal.go
@@ -109,11 +109,6 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
 	}
 	seal.ctx = ctx
 
-	shellPath := "/bin/sh"
-	if s, ok := sys.LookupEnv(shell); ok && path.IsAbs(s) {
-		shellPath = s
-	}
-
 	{
 		// encode initial configuration for state tracking
 		ct := new(bytes.Buffer)
@@ -130,10 +125,6 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
 			fmt.Sprintf("aid %d out of range", config.Confinement.AppID))
 	}
 
-	/*
-		Resolve post-fsu user state
-	*/
-
 	seal.user = fsuUser{
 		aid:      newInt(config.Confinement.AppID),
 		data:     config.Confinement.Outer,
@@ -169,9 +160,14 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
 		}
 	}
 
-	/*
-		Resolve initial container state
-	*/
+	// this also falls back to host path if encountering an invalid path
+	if !path.IsAbs(config.Confinement.Shell) {
+		config.Confinement.Shell = "/bin/sh"
+		if s, ok := sys.LookupEnv(shell); ok && path.IsAbs(s) {
+			config.Confinement.Shell = s
+		}
+	}
+	// do not use the value of shell before this point
 
 	// permissive defaults
 	if config.Confinement.Sandbox == nil {
@@ -186,7 +182,7 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
 					config.Path = p
 				}
 			} else {
-				config.Path = shellPath
+				config.Path = config.Confinement.Shell
 			}
 		}
 
@@ -256,7 +252,6 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
 		if seal.env == nil {
 			seal.env = make(map[string]string, 1<<6)
 		}
-		seal.env[shell] = shellPath
 	}
 
 	/*
@@ -323,9 +318,10 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
 	seal.container.Dir = homeDir
 	seal.env["HOME"] = homeDir
 	seal.env["USER"] = username
+	seal.env[shell] = config.Confinement.Shell
 
 	seal.container.Place("/etc/passwd",
-		[]byte(username+":x:"+mapuid.String()+":"+mapgid.String()+":Fortify:"+homeDir+":"+shellPath+"\n"))
+		[]byte(username+":x:"+mapuid.String()+":"+mapgid.String()+":Fortify:"+homeDir+":"+config.Confinement.Shell+"\n"))
 	seal.container.Place("/etc/group",
 		[]byte("fortify:x:"+mapgid.String()+":\n"))
 
diff --git a/print_test.go b/print_test.go
index 06f67db..b2e5998 100644
--- a/print_test.go
+++ b/print_test.go
@@ -202,6 +202,7 @@ App
       "username": "chronos",
       "home_inner": "/var/lib/fortify",
       "home": "/var/lib/persist/home/org.chromium.Chromium",
+      "shell": "/run/current-system/sw/bin/zsh",
       "sandbox": {
         "hostname": "localhost",
         "seccomp": 32,
@@ -326,6 +327,7 @@ App
     "username": "chronos",
     "home_inner": "/var/lib/fortify",
     "home": "/var/lib/persist/home/org.chromium.Chromium",
+    "shell": "/run/current-system/sw/bin/zsh",
     "sandbox": {
       "hostname": "localhost",
       "seccomp": 32,
@@ -504,6 +506,7 @@ func Test_printPs(t *testing.T) {
         "username": "chronos",
         "home_inner": "/var/lib/fortify",
         "home": "/var/lib/persist/home/org.chromium.Chromium",
+        "shell": "/run/current-system/sw/bin/zsh",
         "sandbox": {
           "hostname": "localhost",
           "seccomp": 32,