The Problem: Running Random GitHub Code Safely

As developers, we frequently encounter interesting GitHub repositories, development tools, or scripts that we want to test. However, running` untrusted code directly on our development machines poses significant security risks:

  • Supply chain attacks: Malicious code that modifies system binaries or installs backdoors (like the 2025 Chalk npm package compromise that affected millions of downloads)
  • Data theft: Scripts that scan for SSH keys (passphrase protected or not), API tokens, or sensitive files
  • System compromise: Privilege escalation attacks that gain persistent access
  • Resource abuse: Cryptocurrency miners or botnet participation

Traditional solutions like virtual machines are heavyweight and slow to reset. Docker provides isolation but shares the kernel and can be escaped. ChromeOS’s unique architecture offers a compelling alternative through its layered container system.

ChromeOS Container Architecture: Defense in Depth

ChromeOS provides multiple layers of isolation that make it ideal for secure sandboxing:

┌────────────────────────────────────────-─────┐
│              ChromeOS (Host)                 │
│  ┌─────────────────────────────────────────┐ │
│  │           Termina VM                    │ │
│  │  ┌─────────────┐  ┌─────────────────────┤ │
│  │  │   Penguin   │  │        OSS          │ │
│  │  │  (Trusted)  │  │   (Untrusted)       │ │
│  │  │             │  │                     │ │
│  │  │ - Your work │  │ - Random GitHub     │ │
│  │  │ - SSH keys  │  │   repositories      │ │
│  │  │ - Configs   │  │ - Untested tools    │ │
│  │  │             │  │ - No sensitive      │ │
│  │  │             │  │   data              │ │
│  │  └─────────────┘  └─────────────────────┤ │
│  └─────────────────────────────────────────┘ │
└─────────────────────────────────────────-────┘

Or a second ascii-art way of outlining the same situation, with more detail ()

ChromeOS (host)
 └─ crosvm (VM with KVM acceleration if hardware supports it)
     └─ Termina (tiny VM OS, runs LXD daemon and socket)
         │    └- uses LXD API to query kernel level cgroups/namespaces
         │    └- avoids trusting oss's /bin/ps /bin/find etc
         │         
         ├─ oss       (Debian container, untrusted)
         │    └─ [supply-chain attacker could replace ps/find/ls]
         │
         └─ penguin   (main Debian container, trusted code)

Complete Setup Process

Prerequisites

This setup must be run in ChromeOS’s Termina VM, not inside a container. You can access this by pressing ctrl-alt-t and the resulting terminal should say “Welcome to crosh, the ChromeOS developer shell.” You should see a prompt like crosh>

Quick Start Script

There’s no vi, emacs or nano in chrosh. You’ll prepare scripts elsewhere and email them to yourself. You’ll use ChromeOS’ regular mail app to read those, as you logged in with your google account after all. The ChromeOS text editor is a bit weak for my liking, and I like to keep a copy of things that may get refined and are not canonically in source control.

cat > /tmp/filename_as_instructed.sh << 'SETUP_SCRIPT_EOF' | bash
The bash code below 
SETUP_SCRIPT_EOF

Save this as /tmp/setup-secure-containers.sh and run it with bash /tmp/setup-secure-containers.sh as you can’t make it executable:

#!/bin/bash
# ChromeOS Secure Container Setup
# This creates two containers:
# - penguin (default/trusted) - your main work environment  
# - oss (untrusted) - for running cloned repos and untrusted code

# IMPORTANT: This script must be run in Termina (the ChromeOS VM)
# because lxc commands don't work from inside containers

set -e

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

echo "================================================="
echo "ChromeOS Secure Container Setup"
echo "================================================="
echo ""
echo "This script will create a two-container security setup:"
echo "- penguin: Your trusted container (already exists)"
echo "- oss: Untrusted container for running random code"
echo ""

# Verify we're in Termina
if ! command -v lxc &> /dev/null; then
    echo "ERROR: lxc command not found. This script must be run in Termina"
    echo "Open the Terminal app in ChromeOS and run this script there."
    exit 1
fi

echo "Environment check passed - lxc command found"

# Step 1: Show current containers
echo ""
echo "Step 1: Current container status"
echo "================================"
lxc list

# Step 2: Get available images
echo ""
echo "Step 2: Finding Debian image..."
echo "==============================="
IMAGE_FINGERPRINT=$(lxc image list --format csv | grep -i debian | cut -d',' -f2 | head -1)

if [ -z "$IMAGE_FINGERPRINT" ]; then
    echo "No Debian image found. Available images:"
    lxc image list
    exit 1
fi

# Step 3: Create the oss container
echo ""
echo "Step 3: Creating oss container..."
echo "=================================="

# Check if oss container already exists
if lxc info oss &>/dev/null; then
    echo "Container 'oss' already exists, skipping..."
else
    echo "Creating 'oss' container..."
    lxc launch $IMAGE_FINGERPRINT oss
    echo "Waiting for container to start..."
    sleep 5
fi

# Show updated container list
echo ""
lxc list

echo ""
echo "Step 4: Setting resource limits for oss container..."
echo "===================================================="

# Set resource limits and security restrictions
lxc config set oss limits.cpu 2
lxc config set oss limits.memory 2GB
lxc config set oss security.nesting false
lxc config set oss security.privileged false

echo "Resource limits and security restrictions applied to oss container"

echo ""
echo "Step 5: Setting up oss container for untrusted code..."
echo "====================================================="

# Install packages in oss container
lxc exec oss -- apt-get update
lxc exec oss -- apt-get install -y git build-essential python3 python3-pip curl wget nodejs npm
lxc exec oss -- mkdir -p /workspace
lxc exec oss -- bash -c "echo 'Untrusted code workspace - Only run random GitHub repos here!' > /workspace/README.txt"

echo "OSS container setup complete"

# Step 6: Set up baseline in trusted container (penguin)
echo ""
echo "Step 6: Creating baseline in penguin (trusted container)..."
echo "=========================================================="

# Create baseline hashes for binary integrity monitoring
lxc exec penguin -- bash -c "find /bin /usr/bin -type f -executable -exec sha256sum {} \; > /root/baseline_hashes.txt"
lxc exec penguin -- bash -c "echo 'Baseline created at $(date)' >> /root/baseline_hashes.txt"
lxc exec penguin -- bash -c "wc -l < /root/baseline_hashes.txt | xargs -I {} echo 'Baseline hash count: {}'"

# Ensure penguin has essential tools
lxc exec penguin -- apt-get update
lxc exec penguin -- apt-get install -y vim git

echo "Baseline created in penguin container"

# Step 7: Create monitoring script in Termina
echo ""
echo "Step 7: Creating Termina-based monitoring script..."
echo "================================================"

cat > /tmp/monitor-containers.sh << 'MONITOR_EOF'
#!/bin/bash
# Container Security Monitor - Runs in Termina
# Monitors the oss (untrusted) and penguin (trusted) containers for supply chain attacks

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

function setup_baseline() {
    local baseline_file="/tmp/.container_baseline"
    
    if [ ! -f "$baseline_file" ]; then
        echo "Creating baseline for binary integrity monitoring..."
        echo "# Container Security Baseline - Created $(date)" > "$baseline_file"
        
        # Create baseline for both containers
        for container in oss penguin; do
            if lxc info "$container" &>/dev/null; then
                echo "# $container container baseline" >> "$baseline_file"
                for binary in /bin/bash /bin/sh /usr/bin/python3 /usr/bin/node /usr/bin/git; do
                    hash=$(lxc exec $container -- sha256sum $binary 2>/dev/null | awk '{print $1}')
                    if [ -n "$hash" ]; then
                        echo "$container:$binary:$hash" >> "$baseline_file"
                    fi
                done
            fi
        done
        echo "Baseline created at $baseline_file"
    fi
}

function check_binary_integrity() {
    local container=$1
    local found_issues=0
   
    echo -e "${YELLOW}Binary Integrity Check - $container${NC}"
    
    # Check key binaries against baseline
    while IFS=: read -r base_container base_binary base_hash; do
        if [[ "$base_container" == "$container" ]] && [[ "$base_binary" =~ ^/.*$ ]]; then
            current_hash=$(lxc exec $container -- sha256sum $base_binary 2>/dev/null | awk '{print $1}')
            if [ -n "$current_hash" ] && [ "$current_hash" != "$base_hash" ]; then
                echo -e "  ${RED}!!!  Modified: $base_binary${NC}"
                echo "    Expected: $base_hash"
                echo "    Current:  $current_hash"
                found_issues=1
            fi
        fi
    done < "/tmp/.container_baseline" 2>/dev/null
    
    if [ $found_issues -eq 0 ]; then
        echo "  All monitored binaries match baseline"
    fi
    
    return $found_issues
}

function check_processes() {
    local container=$1
    echo -e "${YELLOW}Process Check - $container${NC}"
    echo "  Top processes:"
    
    # Show top CPU-consuming processes
    lxc exec $container -- ps aux --sort=-%cpu 2>/dev/null | head -6 | while IFS= read -r line; do
        echo "    $line"
    done
}

function check_network() {
    local container=$1
    echo -e "${YELLOW}Network Connections - $container${NC}"
   
    # Count listening ports and established connections
    listening=$(lxc exec $container -- ss -tlnp 2>/dev/null | grep LISTEN | wc -l)
    connections=$(lxc exec $container -- ss -tnp 2>/dev/null | grep ESTAB | wc -l)
    
    echo "  Listening ports: $listening"
    echo "  Active connections: $connections"
    
    # Alert on any external connections from untrusted container
    if [ "$container" = "oss" ] && [ "$connections" -gt 0 ]; then
        echo -e "  ${RED}!!!  External connections detected in untrusted container:${NC}"
        lxc exec $container -- ss -tnp 2>/dev/null | grep ESTAB | while IFS= read -r line; do
            echo "    $line"
        done
    fi
}

function check_recent_files() {
    local container=$1
    echo -e "${YELLOW}Recently Modified Files - $container${NC}"
    echo "  Files modified in last 10 minutes:"
   
    # Focus on system directories for supply chain attacks
    lxc exec $container -- find /bin /usr/bin /lib -xdev -type f -mmin -10 2>/dev/null | while IFS= read -r line; do
        echo "    $line"
    done
    
    # Also check workspace for oss
    if [ "$container" = "oss" ]; then
        echo "  Workspace files:"
        lxc exec $container -- find /workspace -xdev -type f -mmin -10 2>/dev/null | head -5 | while IFS= read -r line; do
            echo "    $line"
        done
    fi
}

function check_suspicious_files() {
    local container=$1
    echo -e "${YELLOW}Suspicious Files Check - $container${NC}"
    
    # Look for hidden files in tmp directories
    suspicious_count=$(lxc exec $container -- find /tmp /var/tmp /dev/shm -name ".*" -type f 2>/dev/null | wc -l)
    
    if [ "$suspicious_count" -gt 0 ]; then
        echo -e "  ${RED}!!!  Found $suspicious_count hidden files in temp directories${NC}"
    else
        echo "  No suspicious hidden files found"
    fi
}

function check_suid_changes() {
    local container=$1
    
    # Check for new SUID binaries
    lxc exec $container -- find / -xdev -perm -4000 -type f 2>/dev/null | while read suid_file; do
        echo "    SUID: $suid_file"
    done
}

function setup_suid_baseline() {
    for container in oss penguin; do
        if lxc info "$container" &>/dev/null; then
            if [ ! -f "/tmp/.known_suid_$container" ]; then
                lxc exec $container -- find / -xdev -perm -4000 -type f 2>/dev/null > "/tmp/.known_suid_$container"
            fi
        fi
    done
}

# Main monitoring loop
echo "================================================="
echo "Container Security Monitor"
echo "================================================="
echo "Monitoring for supply chain attacks in:"
echo "  - oss (untrusted) - where you run random code"
echo "  - penguin (trusted) - your main environment"
echo ""

# Setup baselines on first run
setup_baseline
setup_suid_baseline

while true; do
    clear
    echo "Container Security Monitor - $(date)"
    echo "====================================="
    echo ""
   
    # Monitor the untrusted container more closely
    echo -e "${RED}=== OSS Container (UNTRUSTED) ===${NC}"
    if ! check_binary_integrity "oss"; then
        echo -e "\n${RED}!!!  ALERT: Binary modification detected in OSS container!${NC}"
        echo -e "${RED}This could indicate a supply chain attack from recently run code${NC}\n"
    fi
    echo ""
    check_processes "oss"
    echo ""
    check_network "oss"
    echo ""
    check_recent_files "oss"
    echo ""
    check_suspicious_files "oss"
   
    echo ""
    echo -e "${GREEN}=== Penguin Container (TRUSTED) ===${NC}"
    if ! check_binary_integrity "penguin"; then
        echo -e "\n${RED}!!!  CRITICAL: Binary modification in TRUSTED container!${NC}\n"
    fi
    echo ""
    check_network "penguin"
   
    echo ""
    echo "Next scan in 30 seconds... (Press Ctrl+C to exit)"
    sleep 30
done
MONITOR_EOF

chmod +x /tmp/monitor-containers.sh
echo "Monitoring script created at /tmp/monitor-containers.sh"

# Step 8: Create helper scripts
echo ""
echo "Step 8: Creating helper scripts..."
echo "=================================="

# Create a script to enter each container
cat > /tmp/enter-oss.sh << 'ENTER_OSS_EOF'
#!/bin/bash
echo "========================================="
echo "Entering OSS (UNTRUSTED) Container"
echo "========================================="
echo "!!!  SECURITY WARNING:"
echo "- Only run untrusted code here"
echo "- No sensitive files or keys"
echo "- Monitor with: bash /tmp/monitor-containers.sh"
echo "========================================="
lxc exec oss -- bash
ENTER_OSS_EOF

chmod +x /tmp/enter-oss.sh

cat > /tmp/enter-penguin.sh << 'ENTER_PENGUIN_EOF'
#!/bin/bash
echo "========================================="
echo "Entering Penguin (TRUSTED) Container"
echo "========================================="
echo "This is your trusted development environment"
echo "========================================="
lxc exec penguin -- bash
ENTER_PENGUIN_EOF

chmod +x /tmp/enter-penguin.sh

# Create status script
cat > /tmp/status.sh << 'STATUS_EOF'
#!/bin/bash
echo "Container Security Setup Status"
echo "==============================="
lxc list
echo ""
echo "OSS Container Security Settings:"
echo "  CPU limit: $(lxc config get oss limits.cpu)"
echo "  Memory limit: $(lxc config get oss limits.memory)"
echo "  Privileged: $(lxc config get oss security.privileged)"
echo "  Nesting: $(lxc config get oss security.nesting)"
echo ""
echo "Quick security check:"
for container in oss penguin; do
    echo -n "  $container binary integrity: "
    ps_hash=$(lxc exec $container -- sha256sum /bin/ps 2>/dev/null | awk '{print substr($1,1,8)}')
    echo "$ps_hash"
done
STATUS_EOF

chmod +x /tmp/status.sh

# Create a reset script for the oss container
cat > /tmp/reset-oss.sh << 'RESET_EOF'
#!/bin/bash
echo "This will destroy and recreate the OSS container"
echo "Any data in the OSS container will be lost!"
read -p "Are you sure? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
    echo "Resetting OSS container..."
    lxc stop oss
    lxc delete oss
    
    # Recreate with same settings
    IMAGE_FP=$(lxc image list --format csv | grep -i debian | cut -d',' -f2 | head -1)
    lxc launch $IMAGE_FP oss
    
    # Reapply security settings
    lxc config set oss limits.cpu 2
    lxc config set oss limits.memory 2GB
    lxc config set oss security.nesting false
    lxc config set oss security.privileged false
    
    # Reinstall packages
    lxc exec oss -- apt-get update
    lxc exec oss -- apt-get install -y git build-essential python3 python3-pip curl wget nodejs npm
    lxc exec oss -- mkdir -p /workspace
    
    echo "OSS container reset complete"
    
    # Update baseline
    rm -f /tmp/.container_baseline
    echo "Run: bash /tmp/monitor-containers.sh to recreate baseline"
fi
RESET_EOF

chmod +x /tmp/reset-oss.sh

# Step 9: Optional SSH Setup for OSS Container
echo ""
echo "Step 9: Setting up SSH access to OSS (optional)..."
echo "=================================================="

# Install and configure SSH
lxc exec oss -- apt-get install -y openssh-server
lxc exec oss -- rm -f /etc/ssh/sshd_not_to_be_run
lxc exec oss -- ssh-keygen -A
lxc exec oss -- systemctl restart ssh
lxc exec oss -- systemctl enable ssh

# Create non-root user
lxc exec oss -- useradd -m -s /bin/bash dev 2>/dev/null || true
lxc exec oss -- bash -c "echo 'dev:changeme' | chpasswd"
lxc exec oss -- usermod -aG sudo dev

# Get IP address
OSS_IP=$(lxc list oss -f csv -c 4 | cut -d' ' -f1)
echo ""
echo "SSH access configured:"
echo "  ssh dev@$OSS_IP"
echo "  Default password: changeme (change immediately!)"
echo ""
echo "!!!  WARNING: Never use SSH agent forwarding (-A) with untrusted containers!"

# Final summary
echo ""
echo "Setup Complete!"
echo "==============="
lxc list
echo ""
echo "Available commands:"
echo "  bash /tmp/monitor-containers.sh - Start security monitoring"
echo "  bash /tmp/enter-oss.sh         - Enter untrusted container"
echo "  bash /tmp/enter-penguin.sh     - Enter trusted container"
echo "  bash /tmp/status.sh            - Check security status"
echo "  bash /tmp/reset-oss.sh         - Reset OSS container (if compromised)"
echo ""
echo "Usage pattern:"
echo "1. Run random code ONLY in oss container (bash /tmp/enter-oss.sh)"
echo "2. Keep monitoring running in another terminal (bash /tmp/monitor-containers.sh)"
echo "3. If monitor detects modified binaries, consider using reset script"
echo ""
echo "The monitor will detect:"
echo "- Modified system binaries (supply chain attacks)"
echo "- Suspicious processes and network connections"
echo "- Recently modified files in system directories"
echo "- Hidden files in temporary directories"
echo ""
echo "🔒 Your trusted work remains safe in the penguin container!"

Manual Setup Steps

If you prefer to understand each step, here’s the manual process:

1. Create the Untrusted Container

# Get available image
IMAGE_FP=$(lxc image list --format csv | grep -i debian | cut -d',' -f2 | head -1)

# Create OSS container
lxc launch $IMAGE_FP oss

# Set security restrictions
lxc config set oss limits.cpu 2
lxc config set oss limits.memory 2GB
lxc config set oss security.nesting false
lxc config set oss security.privileged false

2. Install Development Tools

# Update and install common development tools
lxc exec oss -- apt-get update
lxc exec oss -- apt-get install -y git build-essential python3 python3-pip curl wget nodejs npm

# Create workspace directory
lxc exec oss -- mkdir -p /workspace

3. Create Monitoring Script

The monitoring script runs from Termina and watches both containers for signs of compromise:

# Create the monitoring script
cat > /tmp/monitor-containers.sh << 'EOF'
#!/bin/bash
# [Full monitoring script from above]
EOF

chmod +x /tmp/monitor-containers.sh

Troubleshooting Common Issues

Termina Filesystem Issues

Issue: Scripts fail with “Read-only file system” error. Termina’s home directory (~/) is read-only:

Solution: Use /tmp for all scripts which is not read only.

Issue: no editors

Solution pipe to file trick as mentioned.

# Correct - use /tmp
cat > /tmp/script.sh << 'EOF'
...
EOF
bash /tmp/script.sh

SSH Setup

SSH service needs manual setup in containers:

You get into the container using lxc exec container_name -- bash from Termina (crosh):

# In the target container (run via lxc exec)
apt-get install -y openssh-server
rm -f /etc/ssh/sshd_not_to_be_run  # Remove startup blocker
ssh-keygen -A                       # Generate host keys
systemctl restart ssh
systemctl enable ssh
echo 'root:changeme' | chpasswd    # Set password

LXC Command Not Found

Do NOT run from inside penguin or any other container - you need to be in crosh: ctrl-alt-t

Secure Git Access Patterns

You don’t want you SSH private key on the container that may be taken over by ‘chalk’ style actions. At least you don’t want it without a lengthy passphrase, but there are traditional solutions:

The SSH Agent Forwarding Security Risk

Critical Warning: SSH agent forwarding allows untrusted code to use your keys!

While your SSH session with -A flag is active:

  • Malicious code can push to ANY repo you have write access to
  • Can clone ANY private repo you have access to
  • Cannot steal your key, but can USE it

Safer Alternatives for Git Access

# Create separate key for untrusted work
ssh-keygen -t ed25519 -f ~/.ssh/oss_readonly_key -N ""

# Add to GitHub as deploy key (READ-ONLY) for specific repos
# Copy ONLY this key to oss container
lxc exec penguin -- cat /home/USER/.ssh/oss_readonly_key | \
  lxc exec oss -- bash -c "cat > /home/dev/.ssh/id_ed25519 && chmod 600 /home/dev/.ssh/id_ed25519"

Option 2: Fine-Grained Personal Access Tokens

# Create token with minimal permissions (public_repo only)
# Use in oss container:
git clone https://TOKEN@github.com/user/repo.git

Option 3: Time-Limited Agent Forwarding (USE SPARINGLY)

# Only when absolutely necessary for push operations
ssh -A dev@[oss-ip]
# Do your git operation
# EXIT IMMEDIATELY
exit

# Or use confirmation-required keys
ssh-add -c ~/.ssh/id_ed25519  # Requires confirmation for each use

Security Best Practices

What to NEVER Do

  1. Don’t store sensitive data in the OSS container:
    # NEVER DO THIS
    cp ~/.ssh/id_rsa /path/to/oss/container
    
  2. Don’t run trusted code in OSS container:
    # NEVER DO THIS
    lxc exec oss -- git clone git@github.com:yourcompany/private-repo.git
    
  3. Don’t disable monitoring:
    # NEVER DO THIS - Always keep monitoring running
    pkill monitor-containers
    

What to ALWAYS Do

  1. Reset compromised containers:
    # If monitor detects issues
    bash /tmp/reset-oss.sh
    

    Don’t attempt to repair them. Heck, maybe reset with some regularity anyway.

  2. Regularly update baselines:
    # After legitimate updates
    rm /tmp/.container_baseline
    bash /tmp/monitor-containers.sh  # Recreates baseline
    

Container Isolation Rules

Container Purpose SSH Keys Git Configs Sensitive Data
penguin Trusted development Safe Safe Safe
oss Untrusted testing Never Never Never

Git Security Matrix

Operation Penguin (Trusted) OSS (Untrusted) Method
Clone public repos y y HTTPS
Clone private repos y ! Deploy keys only
Push to repos y N Never from OSS
Store SSH keys y N Never
Store PATs y ! Limited scope only
Agent forwarding N/A !️ Brief sessions only

Container Access Patterns

Daily workflow

  1. Terminal App -> penguin # Normal development
  2. Ctrl+Alt+T -> vsh termina -> bash /tmp/enter-oss.sh # Testing
  3. Or ssh from penguin to oss

Security monitoring

Ctrl+Alt+T -> vsh termina -> bash /tmp/monitor-containers.sh

  • Never create shortcuts that bypass security
  • Don’t alias direct access to OSS in penguin
  • Don’t auto-start monitoring (review alerts manually)

Lessons from Production Use

Key Insight: The separation between Termina (VM host) and containers is crucial. Many security solutions try to work entirely within containers, but the real power comes from leveraging the host-level view.

What we learned:

  • Container isolation is only as good as your monitoring for breaches
  • Host-level monitoring provides better security visibility
  • ChromeOS’s architecture is designed for this type of security model

Understanding the Monitoring System

The monitoring system watches for several types of compromise:

1. Binary Integrity Monitoring

I grant you this is underdeveloped at the point of this blog entry.

# Creates baseline hashes of critical binaries
for binary in /bin/bash /bin/sh /usr/bin/python3 /usr/bin/node /usr/bin/git; do
    hash=$(lxc exec $container -- sha256sum $binary 2>/dev/null | awk '{print $1}')
    echo "$container:$binary:$hash" >> ~/.container_baseline
done

What it detects: Supply chain attacks that modify system binaries

Real-world example: The 2024 Chalk npm package compromise replaced legitimate packages with malicious versions that could modify Node.js binaries or install backdoors. Our monitoring would detect such changes immediately.

Example alert:

!!!  Modified: /usr/bin/python3
Expected: a1b2c3d4e5f6...
Current:  x9y8z7w6v5u4...

2. Process Monitoring

# Shows CPU-intensive processes
lxc exec $container -- ps aux --sort=-%cpu | head -6

What it detects: Cryptocurrency miners, botnet activity, unexpected daemons

3. Network Connection Analysis

# Counts active connections
connections=$(lxc exec $container -- ss -tnp | grep ESTAB | wc -l)

What it detects: Data exfiltration, command & control communication, unexpected servers

4. File System Changes

# Finds recently modified system files
lxc exec $container -- find /bin /usr/bin /lib -xdev -type f -mmin -10

What it detects: System file tampering, backdoor installation

5. Hidden File Detection

# Searches for hidden files in temp directories
lxc exec $container -- find /tmp /var/tmp /dev/shm -name ".*" -type f

What it detects: Malware staging areas, credential harvesting tools

Advanced Usage Patterns

Testing Suspicious GitHub Repositories

# 1. Start monitoring (separate terminal)
bash /tmp/monitor-containers.sh

# 2. Enter untrusted container
bash /tmp/enter-oss.sh

# 3. In OSS container, test the repo
cd /workspace
git clone https://github.com/suspicious/repo.git
cd repo
./setup.sh  # This runs in isolation

# 4. Monitor terminal will alert on any suspicious changes
# 5. If compromised, reset the container
exit  # Leave OSS container
bash /tmp/reset-oss.sh

Development Tool Testing

# Test a new development tool safely
bash /tmp/enter-oss.sh

# In OSS container
curl -fsSL https://some-tool.com/install.sh | bash
some-new-tool --help

# Monitor for:
# - Modified binaries
# - Network connections
# - Hidden files
# - Unexpected processes

Multi-Container Workflow

# Terminal 1: Monitoring
bash /tmp/monitor-containers.sh

# Terminal 2: Trusted work
bash /tmp/enter-penguin.sh
# Do your normal development here

# Terminal 3: Untrusted testing
bash /tmp/enter-oss.sh
# Test random GitHub projects here

# Terminal 4: Status checking
bash /tmp/status.sh

Performance Considerations

Resource Limits

The OSS container is intentionally limited to prevent resource abuse:

# Current limits (modify as needed)
lxc config set oss limits.cpu 2        # 2 CPU cores max
lxc config set oss limits.memory 2GB   # 2GB RAM max

Monitoring Overhead

  • Monitoring script uses minimal resources
  • Scans every 30 seconds (configurable)
  • Focuses on security-critical changes only
  • Can run continuously without impact

Container Reset Speed

# Full OSS container reset takes ~2-3 minutes
time bash /tmp/reset-oss.sh
# Includes: stop, delete, recreate, configure, install packages

Integration with Development Workflow

IDE Integration

You can configure your IDE to work with the container setup:

# VS Code with Remote-Containers
# Point to penguin container for trusted development
code --folder-uri vscode-remote://attached-container+penguin/path/to/project

# For untrusted code testing, always use terminal access
bash /tmp/enter-oss.sh

Git Configuration

# In penguin (trusted) - normal git config
git config --global user.name "Your Name"
git config --global user.email "your.email@domain.com"

# In OSS (untrusted) - minimal or fake config only
git config --global user.name "Test User"
git config --global user.email "test@example.com"
# Never configure real credentials

File Sharing Between Containers

# Share files from trusted to untrusted (one-way only)
# Copy from penguin to OSS for testing
lxc file push /path/in/penguin/container/file.txt oss/workspace/

# NEVER copy from OSS to penguin without verification
# Instead, manually recreate verified files in penguin

Extending the Security Model

Custom Monitoring Rules

Add your own detection rules to the monitoring script:

# Example: Monitor for specific file types
function check_crypto_miners() {
    local container=$1
    miners=$(lxc exec $container -- find /tmp -name "*mine*" -o -name "*crypto*" 2>/dev/null | wc -l)
    if [ "$miners" -gt 0 ]; then
        echo -e "${RED}!!!  Potential cryptocurrency miner detected${NC}"
    fi
}

Log Integration

# Enhanced logging in monitoring script
LOG_FILE="$HOME/container-security.log"

function log_alert() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') ALERT: $1" | tee -a "$LOG_FILE"
}

Conclusion

ChromeOS’s layered container architecture provides an excellent foundation for safely testing untrusted code. This setup gives you:

  • True isolation: Each container is properly sandboxed
  • Real-time monitoring: Immediate detection of compromise attempts
  • Easy recovery: Quick container reset when needed
  • Maintained productivity: Your trusted environment stays clean

The key insight is using ChromeOS’s existing security model rather than fighting it. By running the monitoring from Termina and isolating untrusted code in its own container, you get enterprise-grade security with developer-friendly workflows.

All that said, I’m unlikely to use it without the Terminal integration (see below). I’d like to open Terminal then click oss a line below penguin. Instead, I’m probably use a container in podman inside penguin - that seems hardened as a solution and workable today.

The Terminal App Limitation

CromeOS’ Terminal app’s inability to add custom container entries is a significant UX gap. The fact that only penguin appears as a clickable row means:

  • No visual distinction between trusted/untrusted environments
  • Can’t theme the OSS terminal differently (red background would be perfect!)
  • Extra friction to access the untrusted container
  • No way to know at a glance which container you’re in

The SSH workaround (penguin -> ssh dev@oss-ip) adds complexity to what should be a single click.

Security Implications

These UX limitations create real security risks:

  1. Command confusion: Without visual distinction, you might accidentally run trusted commands (like git push with your real credentials) in the untrusted container
  2. Increased attack surface: The SSH workaround opens network ports and adds authentication complexity that could be exploited
  3. Remote access temptation: Lack of remote access means you might be tempted to run untrusted code directly on your primary machine when traveling, defeating the entire security model

I would really want to be able to make a second container from within the Terminal app. The UX hints that it should be possible but the feature is not there. A huge shame given how incredibly strong the dev experience on ChromeBooks (that have enough RAM and SSD).

The Chrome Remote Desktop Problem

This is even more frustrating. A ChromeOS Flex machine effectively becomes an island because, only Windows and Mac are first-class choices for destination for Chrome Remote Desktop. HOST-OS Linux is a second class choice because one seems to need PhD-level understanding of X11/Wayland/DISPLAY. Multi-user possibilities might be one of complexities, and systemd could be on the “complicating” mix too.

Chrome Remote Desktop TO ChromeOS/Linux (the very platform Google controls!) is not supported at all.

Yet, Chrome Remote Desktop FROM ChromeOS to Windows or Mac is supported.

This means you can’t remotely access your secure container (in ChromeOS Flex on a spare PC) from your Chromebook when traveling, defeating much of the purpose of having a dedicated security testing environment. Potential Workarounds (all imperfect). Or from your Mac or Windows laptop which support Chrome Remoting as an origin just fine.

For Terminal access I could create a web-based terminal (ttyd or similar) in each container, accessible via different ports, but I’d rather be in my terminal of choice: Terminal

I have other VNC server in penguin or Guacamole, too, but I wish this were a mainstream feature of ChromeOS once you’ve enabled developer features.

The irony is that Google has all the pieces (Crostini, Chrome Remote Desktop, Terminal app) but hasn’t connected them properly. A simple “Add Container to Terminal” button and proper Chrome Remote Desktop support would solve everything. It’s particularly galling because ChromeOS is supposed to be the “simple, secure” option, yet these limitations push us toward complex workarounds that probably decrease security.

Googlers

And if any Googlers have got this far: can you have an explicit “Disable trackpad while typing” setting as macOS Sierra had. It was removed after sierra. Chromebooks have plastic chassis and mild weight adjacent to the trackpad while typing can cause a click at current pointer position.



Published

September 18th, 2025
Reads: