# How to Configure SELinux Labels for Docker Mounts Using the `selinuxLabel` Option in Sandcastle

> Master SELinux labels for Docker mounts in Sandcastle. Learn to use the selinuxLabel option with "z", "Z", or false for optimal security and context management. Secure your Docker sandbox.

- Repository: [Matt Pocock/sandcastle](https://github.com/mattpocock/sandcastle)
- Tags: how-to-guide
- Published: 2026-05-24

---

**Set the `selinuxLabel` option to `"z"` for shared SELinux contexts, `"Z"` for private contexts, or `false` to disable labeling entirely when mounting volumes into Sandcastle's Docker sandbox.**

Sandcastle is an open-source framework for running agentic code in sandboxed containers. When using the Docker provider on SELinux-enabled hosts like RHEL, CentOS, or Fedora, the `selinuxLabel` configuration option controls the security context suffix appended to bind mounts, preventing permission errors while maintaining appropriate filesystem access controls.

## Where the `selinuxLabel` Option Is Defined

The SELinux labeling configuration is split between type definitions in [`src/mountUtils.ts`](https://github.com/mattpocock/sandcastle/blob/main/src/mountUtils.ts) and the Docker provider implementation in [`src/sandboxes/docker.ts`](https://github.com/mattpocock/sandcastle/blob/main/src/sandboxes/docker.ts).

### The `SelinuxLabel` Type Definition

In [`src/mountUtils.ts`](https://github.com/mattpocock/sandcastle/blob/main/src/mountUtils.ts), the `SelinuxLabel` type restricts the option to three valid values:

```typescript
export type SelinuxLabel = "z" | "Z" | false;

```

This union type ensures compile-time safety, allowing only the shared label character (`"z"`), the private label character (`"Z"`), or explicit disabling (`false`).

### The `DockerOptions` Interface

The `docker()` factory function accepts configuration through the `DockerOptions` interface located in [`src/sandboxes/docker.ts`](https://github.com/mattpocock/sandcastle/blob/main/src/sandboxes/docker.ts):

```typescript
export interface DockerOptions {
  // ... other configuration options
  /** SELinux volume label suffix applied to bind mounts. */
  readonly selinuxLabel?: SelinuxLabel;
}

```

## How SELinux Labels Are Applied to Mounts

When Sandcastle constructs the Docker run command, it processes each mount through the `formatVolumeMount` function in [`src/mountUtils.ts`](https://github.com/mattpocock/sandcastle/blob/main/src/mountUtils.ts). This utility concatenates the SELinux suffix after other mount options like `ro` (read-only).

```typescript
export const formatVolumeMount = (
  mount: { hostPath: string; sandboxPath: string; readonly?: boolean },
  selinuxLabel: SelinuxLabel | undefined,
): string => {
  const base = `${mount.hostPath}:${mount.sandboxPath}`;
  const options = [mount.readonly ? "ro" : undefined, selinuxLabel || undefined]
    .filter((option): option is string => option !== undefined)
    .join(",");

  return options ? `${base}:${options}` : base;
};

```

The function produces Docker volume strings following these rules:

- **`"z"`** → Appends `:z` for shared SELinux labeling, allowing multiple containers to access the files with the same context
- **`"Z"`** → Appends `:Z` for private SELinux labeling, restricting the mount to an unshared context exclusive to the container
- **`false`** → Omits any SELinux suffix, resulting in a standard mount without security context modification

## Configuration Examples

You can configure SELinux labeling when initializing the Docker sandbox provider. If omitted, Sandcastle automatically applies shared labeling.

### Using the Default Shared Label (`z`)

When you call `docker()` without specifying `selinuxLabel`, Sandcastle defaults to `"z"` as implemented in the provider's constructor in [`src/sandboxes/docker.ts`](https://github.com/mattpocock/sandcastle/blob/main/src/sandboxes/docker.ts):

```typescript
import { docker } from "sandcastle/sandboxes/docker";

await run({
  agent: claudeCode("claude-opus-4-7"),
  sandbox: docker(), // selinuxLabel defaults to "z"
});

```

This generates mount strings ending with `:z`, suitable for most development scenarios where the container needs to read and write files without changing their security context globally.

### Configuring a Private Label (`Z`)

For scenarios requiring isolated security contexts—such as when handling sensitive data across multiple containers—set `selinuxLabel` to `"Z"`:

```typescript
import { docker } from "sandcastle/sandboxes/docker";

await run({
  agent: claudeCode("claude-opus-4-7"),
  sandbox: docker({
    selinuxLabel: "Z", // Mount suffix will be :Z
    mounts: [
      { hostPath: "~/my-data", sandboxPath: "/data", readonly: false },
    ],
  }),
});

```

This results in Docker volume strings like `/home/user/data:/data:Z`, ensuring the container uses a private unshared SELinux label that other containers cannot access.

### Disabling SELinux Labeling

To completely bypass SELinux relabeling—useful for hosts without SELinux or when using alternative security modules like AppArmor—set the option to `false`:

```typescript
import { docker } from "sandcastle/sandboxes/docker";

await run({
  agent: claudeCode("claude-opus-4-7"),
  sandbox: docker({
    selinuxLabel: false, // No :z or :Z suffix appended
  }),
});

```

The resulting Docker command excludes any SELinux suffix, mounting volumes without security context modification.

## Default Behavior

If you do not explicitly provide a `selinuxLabel` in your configuration, Sandcastle automatically falls back to `"z"` (shared labeling). This default is established in [`src/sandboxes/docker.ts`](https://github.com/mattpocock/sandcastle/blob/main/src/sandboxes/docker.ts) using the nullish coalescing operator:

```typescript
const selinuxLabel = options?.selinuxLabel ?? "z";

```

This conservative default prevents the permission denials that occur on SELinux-enforcing systems when labels are missing, while maintaining compatibility across different Linux distributions.

## Summary

- **Configure SELinux labels** using the `selinuxLabel` option in the `docker()` factory function to control how bind mounts are labeled in the container runtime.
- **Choose `"z"`** for shared contexts that multiple containers can access, `"Z"` for private contexts isolated to a single container, or `false` to disable SELinux labeling entirely.
- **Implementation** relies on [`src/mountUtils.ts`](https://github.com/mattpocock/sandcastle/blob/main/src/mountUtils.ts) for the `SelinuxLabel` type and `formatVolumeMount` logic, while [`src/sandboxes/docker.ts`](https://github.com/mattpocock/sandcastle/blob/main/src/sandboxes/docker.ts) handles the default `"z"` fallback.
- **Type safety** is enforced through the `SelinuxLabel` union type, restricting values to `"z"`, `"Z"`, or `false` at compile time.

## Frequently Asked Questions

### What happens if I don't specify `selinuxLabel` in my Sandcastle configuration?

Sandcastle defaults to `"z"` (shared labeling). According to the source code in [`src/sandboxes/docker.ts`](https://github.com/mattpocock/sandcastle/blob/main/src/sandboxes/docker.ts), the provider checks `options?.selinuxLabel ?? "z"`, which means undefined values automatically resolve to the shared label suffix, ensuring consistent behavior across SELinux-enabled hosts.

### When should I use `"Z"` instead of `"z"` for SELinux labels?

Use `"Z"` (private label) when you want the mounted content to use an unshared SELinux context that only the current container can access. Use `"z"` (shared label) when multiple containers need to access the same files, or when you want the container to interact with files that other non-containerized processes also use. Private labels prevent security context leakage between containers.

### Does the Podman provider in Sandcastle support the same SELinux options?

Yes. The Podman sandbox provider in [`src/sandboxes/podman.ts`](https://github.com/mattpocock/sandcastle/blob/main/src/sandboxes/podman.ts) mirrors the Docker provider's implementation and accepts the same `selinuxLabel` configuration. Both providers import and utilize the `SelinuxLabel` type and `formatVolumeMount` function from [`src/mountUtils.ts`](https://github.com/mattpocock/sandcastle/blob/main/src/mountUtils.ts), ensuring identical SELinux behavior across container runtimes.

### Can I mix SELinux labels within the same sandbox configuration?

No. The `selinuxLabel` option applies globally to all bind mounts configured for that sandbox instance. Sandcastle processes every mount in the `mounts` array through the same `formatVolumeMount` function call using the single `selinuxLabel` value. If you require different SELinux contexts for different host paths, you must create separate sandbox instances with distinct configurations.