How to Manage Linux Capabilities for Containers on macOS

macOS provides the container CLI to add or drop Linux capabilities when creating or running containers, using the --cap-add and --cap-drop flags to fine-tune process permissions beyond the default restricted set.

The apple/container repository provides a lightweight container runtime for macOS that supports Linux capabilities. You can manage Linux capabilities for containers on macOS using the container command-line interface, which accepts standard Docker-like flags to customize the permission set available to containerized processes according to the source documentation.

Default Linux Capabilities on macOS

By default, containers started on macOS receive a restricted set of Linux capabilities. As documented in docs/how-to.md, the default permitted set includes:

  • CAP_AUDIT_WRITE
  • CAP_CHOWN
  • CAP_DAC_OVERRIDE
  • CAP_FOWNER
  • CAP_FSETID
  • CAP_KILL
  • CAP_MKNOD
  • CAP_NET_BIND_SERVICE
  • CAP_NET_RAW
  • CAP_SETFCAP
  • CAP_SETGID
  • CAP_SETPCAP
  • CAP_SETUID
  • CAP_SYS_CHROOT

This default set provides basic privileges while maintaining security boundaries, but you can modify it using the capability management flags.

Adding and Dropping Capabilities

The container CLI supports two flags for capability management, documented in both docs/how-to.md and docs/command-reference.md:

--cap-add <cap> - Adds a capability to the container's permitted set. The name can be written with or without the CAP_ prefix and is case-insensitive.

--cap-drop <cap> - Removes a capability from the default set.

Both flags are accepted by the container run and container create commands.

Syntax and Formatting

Capability names are case-insensitive and flexible in formatting. For example, NET_ADMIN, net_admin, and CAP_NET_ADMIN are all valid when passed to --cap-add or --cap-drop.

Capability Ordering Semantics

When you specify multiple capability modifications, the runtime applies all --cap-drop operations first, then all --cap-add operations. This ordering has specific implications:

  • --cap-drop ALL --cap-add ALL results in all capabilities being granted (the drop happens first, then the add restores everything)
  • --cap-drop ALL --cap-add SETUID --cap-add SETGID gives you only the two specified capabilities

This behavior is implemented in the runtime logic and documented in docs/how-to.md.

Common Capability Patterns

Grant All Capabilities

To run a container with full privileges, add all capabilities:

container run --cap-add ALL alpine sh -c "ip link set lo down && echo ok"

This pattern is useful when you need unrestricted access to system resources.

Drop Everything and Selectively Re-add

For maximum security, start with a blank slate and enable only specific capabilities:

container run --cap-drop ALL --cap-add SETUID --cap-add SETGID alpine id

This approach follows the principle of least privilege, granting only the minimum permissions required for your workload.

Grant All Except Specific Capabilities

When you need most privileges but must forbid specific ones:

container run --cap-add ALL --cap-drop NET_ADMIN alpine sh

This pattern keeps the full privilege set while blocking specific dangerous capabilities.

Remove a Single Default Capability

To demonstrate that a capability is indeed removed and enforce restrictions:

container run --cap-drop CHOWN alpine chown 100 /tmp

# → "Operation not permitted"

This command fails because the CHOWN capability has been removed from the container's permitted set.

Implementation Details

The capability flags are processed through the container runtime's IPC layer. According to the source code in Sources/ContainerXPC (specifically XPCServer.swift and XPCClient.swift), the CLI forwards these flags to the XPC server, which manages the container lifecycle.

The wrapper script scripts/update-container.sh demonstrates how the CLI options are passed through to the underlying container binary, ensuring that your capability specifications reach the runtime intact.

Summary

  • Default capabilities: macOS containers start with 14 restricted capabilities including CAP_NET_RAW, CAP_SETUID, and CAP_CHOWN.
  • Management flags: Use --cap-add to grant additional permissions and --cap-drop to remove them.
  • Flexible naming: Capability names accept CAP_ prefix or plain names, case-insensitive.
  • Ordering matters: All drops are applied before adds, allowing complex permission scenarios like "drop all then add specific."
  • Source locations: Documentation resides in docs/how-to.md and docs/command-reference.md, while implementation logic is in Sources/ContainerXPC.

Frequently Asked Questions

What are the default Linux capabilities for containers on macOS?

By default, macOS containers receive a restricted set of 14 capabilities including CAP_AUDIT_WRITE, CAP_CHOWN, CAP_DAC_OVERRIDE, CAP_FOWNER, CAP_FSETID, CAP_KILL, CAP_MKNOD, CAP_NET_BIND_SERVICE, CAP_NET_RAW, CAP_SETFCAP, CAP_SETGID, CAP_SETPCAP, CAP_SETUID, and CAP_SYS_CHROOT. This set is defined in the docs/how-to.md file and provides basic container functionality while maintaining security boundaries.

How do I grant all Linux capabilities to a container on macOS?

Use the --cap-add ALL flag when running or creating a container: container run --cap-add ALL alpine sh. This grants every available Linux capability to the container process, effectively giving it full privileges similar to running as root without restrictions.

Can I remove specific capabilities from the default set?

Yes, use the --cap-drop flag followed by the capability name. For example, container run --cap-drop CHOWN alpine chown 100 /tmp removes the CHOWN capability, causing chown operations to fail with "Operation not permitted". You can drop multiple capabilities by specifying the flag multiple times.

In what order are capability modifications applied?

All --cap-drop operations are applied first, followed by all --cap-add operations. This means that --cap-drop ALL --cap-add SETUID results in only the SETUID capability being granted, while --cap-add ALL --cap-drop NET_ADMIN grants all capabilities except NET_ADMIN. This ordering is documented in docs/how-to.md and enforced by the runtime implementation in Sources/ContainerXPC.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →