Skip to main content
Container Kit leverages Tauri’s security model, Rust’s memory safety, and macOS sandboxing to provide a secure desktop application for container management.

Security Architecture

Multi-Layer Security

Container Kit implements security at multiple layers:
1

Frontend Security

TypeScript with strict typing prevents many runtime errors and type confusion attacks.
2

IPC Boundary

Tauri’s command system validates all messages between frontend and backend.
3

Rust Memory Safety

Rust’s ownership model prevents buffer overflows, use-after-free, and data races.
4

macOS Sandboxing

Application runs with limited permissions, requesting access only when needed.

Tauri Security Model

Content Security Policy

Tauri enforces a Content Security Policy to prevent XSS attacks:
tauri.conf.json
{
  "app": {
    "security": {
      "csp": null
    }
  }
}
In production, configure a strict CSP to prevent inline scripts and unauthorized resource loading.

Command Allowlist

Only explicitly registered Tauri commands are accessible from the frontend:
src-tauri/src/lib.rs
let spectabuilder = Builder::<tauri::Wry>::new().commands(collect_commands![
    greet,
    run_container_command_with_stdin,
    execute_with_elevated_command,
    get_default_shell,
    stream_container_command
]);

builder
    .invoke_handler(spectabuilder.invoke_handler())
    .run(tauri::generate_context!())
Never expose commands that execute arbitrary shell commands without validation.

Type-Safe IPC

All commands use Specta for compile-time type safety:
#[tauri::command]
#[specta::specta]
pub async fn execute_with_elevated_command(
    command: String,
    args: Vec<String>,
) -> Result<CommandResult, String> {
    // Implementation
}
TypeScript bindings are automatically generated:
src/lib/models/bindings.ts
export async function execute_with_elevated_command(
    command: string,
    args: string[]
): Promise<CommandResult>

Privilege Escalation

Container operations often require elevated privileges. Container Kit handles this securely:

Elevated Command Execution

src-tauri/src/commands/system.rs
use elevated_command::Command;

#[tauri::command]
#[specta::specta]
pub async fn execute_with_elevated_command(
    command: String,
    args: Vec<String>,
) -> Result<CommandResult, String> {
    let is_elevated = Command::is_elevated();

    let mut cmd = StdCommand::new(&command);
    cmd.args(&args);

    let output = if is_elevated {
        // Already elevated - execute directly
        cmd.output().map_err(|e| e.to_string())?
    } else {
        // Request elevation with macOS system prompt
        let mut elevated_cmd = Command::new(cmd);
        elevated_cmd.name("ContainerKit".to_string());
        elevated_cmd.icon(include_bytes!("../../icons/icon.icns").to_vec());
        elevated_cmd.output().map_err(|e| e.to_string())?
    };

    Ok(CommandResult {
        signal: output.status.signal(),
        stdout: String::from_utf8_lossy(&output.stdout).to_string(),
        stderr: String::from_utf8_lossy(&output.stderr).to_string(),
        code: output.status.code(),
    })
}

Key Security Features

Checks if the app is already running with elevated privileges before requesting elevation:
let is_elevated = Command::is_elevated();
Uses macOS’s native elevation dialog, showing the app name and icon:
elevated_cmd.name("ContainerKit".to_string());
elevated_cmd.icon(include_bytes!("../../icons/icon.icns").to_vec());
This prevents spoofing and provides clear user consent.
Always validate commands before execution:
// Whitelist allowed commands
const ALLOWED_COMMANDS: &[&str] = &["container", "docker", "podman"];

if !ALLOWED_COMMANDS.contains(&command.as_str()) {
    return Err("Unauthorized command".to_string());
}

Container CLI Security

Sidecar Binary

Container Kit bundles the Apple Container CLI as a sidecar binary:
tauri.conf.json
{
  "bundle": {
    "externalBin": [
      "binaries/sidecar/apple-container/bin/container"
    ],
    "resources": [
      "binaries/sidecar/apple-container/**/*"
    ]
  }
}

Benefits

Version Control

Bundles a specific, tested version of the container CLI, preventing version conflicts.

Path Isolation

Uses bundled binary instead of system PATH, preventing PATH injection attacks.

Integrity

Binary is included in the signed app bundle, verified by macOS Gatekeeper.

No System Dependency

Works without requiring system-wide CLI installation.

Command Execution

src/lib/services/containerization/utils.ts
import { Command } from '@tauri-apps/plugin-shell';

export function createContainerCommand(args: string[]): Command<string> {
    // Uses bundled sidecar binary
    return Command.create('container', args);
}
The sidecar binary path is automatically resolved by Tauri, ensuring consistent execution across environments.

Database Security

Data Protection

The SQLite database is stored in the application data directory:
~/Library/Application Support/com.ethercorps.container-kit/container-kit.db
The database file inherits macOS user-level permissions, readable only by the current user.

Sensitive Data

Never store passwords or secrets in plain text. Use macOS Keychain for sensitive credentials:
import { Store } from '@tauri-apps/plugin-store';

const store = new Store('settings.json');

// Store non-sensitive settings
await store.set('theme', 'dark');

// For passwords, use macOS Keychain instead

Input Validation

Command Arguments

Validate all user input before passing to shell commands:
export function validateContainerId(id: string): boolean {
    // Only allow alphanumeric and common safe characters
    return /^[a-zA-Z0-9_-]+$/.test(id);
}

export async function startContainer(id: string): Promise<Output> {
    if (!validateContainerId(id)) {
        throw new Error('Invalid container ID');
    }
    
    const command = createContainerCommand(['start', id]);
    return await command.execute();
}

User Input Sanitization

export function sanitizeImageName(name: string): string {
    // Remove potentially dangerous characters
    return name.replace(/[^a-zA-Z0-9:._/-]/g, '');
}

export function sanitizeUrl(url: string): string {
    try {
        const parsed = new URL(url);
        // Only allow https and http
        if (!['https:', 'http:'].includes(parsed.protocol)) {
            throw new Error('Invalid protocol');
        }
        return parsed.toString();
    } catch {
        throw new Error('Invalid URL');
    }
}

Hardened Runtime

macOS hardened runtime provides additional security:
tauri.conf.json
{
  "bundle": {
    "macOS": {
      "hardenedRuntime": true,
      "minimumSystemVersion": "26.0"
    }
  }
}

Runtime Protections

1

Code Signing

App is signed with a Developer ID certificate, verified by macOS Gatekeeper.
2

Library Validation

Only Apple-signed or same-team-signed libraries can be loaded.
3

Memory Protections

Prevents code injection and runtime modification.
4

Notarization

App is notarized by Apple, scanned for malware before distribution.

Update Security

Container Kit supports secure auto-updates:
tauri.conf.json
{
  "plugins": {
    "updater": {
      "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6..."
    }
  }
}

Signed Updates

Updates are signed with a private key and verified with the embedded public key:
.plugin(tauri_plugin_updater::Builder::new().build())

Security Checklist

  • Use strict TypeScript configuration
  • Enable Rust clippy and fix all warnings
  • Validate all user input
  • Use parameterized queries
  • Never log sensitive data
  • Review command allowlist
  • Build in release mode for production
  • Enable hardened runtime
  • Sign with valid Developer ID certificate
  • Notarize the app with Apple
  • Generate update signature keys
  • Test on clean macOS installation
  • Serve updates over HTTPS
  • Sign update manifests
  • Document minimum macOS version (26.0+)
  • Provide SHA-256 checksums
  • Maintain changelog of security fixes

Best Practices

Principle of Least Privilege

Request elevated permissions only when necessary, not on app launch.

Defense in Depth

Layer multiple security controls - validation, type safety, sandboxing.

Fail Securely

On errors, deny access rather than falling back to permissive behavior.

Security Updates

Keep dependencies updated and monitor security advisories.

Reporting Security Issues

DO NOT create public GitHub issues for security vulnerabilities.Email security issues to: [email protected]Include:
  • Description of the vulnerability
  • Steps to reproduce
  • Potential impact
  • Suggested fixes (if any)

Next Steps

Performance

Learn about performance optimizations and benchmarking

Architecture

Understand the overall application architecture

Build docs developers (and LLMs) love