Back to Blog

Your AI Agent Has Root Access — Now What?

AI security, AppArmor, Santa

Your AI agent has the same permissions you do. Your SSH keys. Your production credentials. Your /etc/shadow. Your systemd services. If you can modify it, the agent can modify it. And if you haven't confined that access, you're running a non-deterministic process with root-equivalent privileges.

I've been deploying AI agents in production for six months now. Not demos — production systems managing client infrastructure, OAuth tokens, database backups, and ad spend. The first version had zero confinement. The current version runs under AppArmor in enforce mode with 74 active profiles.

Getting there broke pg_dump, taught me that Perl wrappers need read access to language libraries, and required two weeks of log archaeology before I was confident enough to flip from complain mode to enforce.

This is the practitioner's guide to AI agent confinement across three platforms: Linux (what we actually run), macOS (what most developers run), and Windows (what enterprises run). Real configs. Real commands. Real failure modes.

The Problem: Principle of Least Privilege Applies to AI Too

When you run an AI coding agent — Claude Code, Cursor, GitHub Copilot Workspace, Devin, OpenClaw — it executes under your user account with your permissions. That's the Unix security model working exactly as designed: processes inherit the privileges of the user who launched them.

For most software, that's fine. Your text editor doesn't need kernel-level confinement because it's deterministic. You know what it will do. You trust the binary.

AI agents are different. They're non-deterministic. The same prompt can produce different behavior across runs. Prompt injection is unsolved. Jailbreaks happen weekly. Supply chain attacks on AI tool plugins are already documented.

And the blast radius keeps growing. My production agent has access to:

  • AWS credentials via EC2 instance role
  • OAuth tokens for Google Calendar, Gmail, GA4, LinkedIn Ads
  • GitHub PAT with full repo access across 10+ repositories
  • Cloudflare API tokens for 10 domains
  • Database connection strings for production PostgreSQL
  • Client-facing email accounts (Zoho, Gmail)
  • Encrypted vault mount with sensitive credentials

That's a lot of access for a process whose behavior I can't fully predict. The question isn't whether the AI will do something unexpected — it's whether my system stops it when it does.

Confinement vs Alignment

Alignment is about intent. Does the model want to do the right thing? Modern LLMs are pretty good here.

Confinement is about capability. Can the process do the wrong thing, regardless of intent? That's what we're solving.

You don't rely on the AI's good behavior. You enforce boundaries at the OS level that the process cannot override.

Linux: AppArmor in Production

We run Ubuntu 24.04 on AWS EC2. AppArmor ships with the kernel. It's a mandatory access control (MAC) system that restricts processes based on profiles — whitelist-style rules that define what a process can and cannot access.

Unlike discretionary access control (DAC) — standard Unix permissions where the user owns the access decision — MAC is enforced by the kernel. Even root-owned processes can be confined.

Current Status

$ sudo aa-status
apparmor module is loaded.
74 profiles are loaded.
74 profiles are in enforce mode.
2 profiles are in complain mode.

Those 2 profiles in complain mode are snap-managed services. Flipping them to enforce would be a no-op — they log violations but don't actually need enforcement in our environment.

The 74 enforced profiles include system services (systemd, snap daemons, network services) and the custom profile for our AI agent process.

Implementation Path: Complain → Audit → Enforce

AppArmor has two modes:

  • Complain mode: Logs violations but allows the operation to proceed
  • Enforce mode: Blocks violations and logs them

You start in complain mode. Always. If you write a profile from scratch and switch directly to enforce, you will break things. Guaranteed.

Our process:

  1. Deploy the profile in complain mode. Let the agent run for 2+ weeks doing everything it normally does.
  2. Audit every log. We checked:
    • /var/log/audit/audit.log (auditd captures AppArmor events)
    • dmesg | grep -i apparmor
    • journalctl | grep -i apparmor
    • /var/log/syslog
    • /var/log/kern.log
  3. Zero violations = ready for enforce. After two weeks, we had zero logged denials. Switched to enforce mode.

The profile explicitly denies:

  • /etc/shadow (password hashes)
  • /etc/sudoers and /etc/sudoers.d/** (privilege escalation)
  • ~/.ssh/** write access (can read public keys, cannot modify private keys)
  • /etc/systemd/** write access (cannot create or modify services)
  • /var/spool/cron/** and /etc/cron.*/** write access (cannot schedule tasks)
  • Network access to internal EC2 metadata endpoint (blocks SSRF to 169.254.169.254)

Example snippet from the profile:

# Allow read access to necessary system libraries
/usr/lib/** r,
/lib/** r,

# Allow read access to workspace and git repos
/home/ubuntu/.openclaw/workspace/** rw,
/home/ubuntu/.openclaw/workspace/.git/** rw,

# Deny password and privilege escalation files
deny /etc/shadow r,
deny /etc/sudoers r,
deny /etc/sudoers.d/** r,

# Allow SSH public key reads, deny private key writes
/home/ubuntu/.ssh/*.pub r,
deny /home/ubuntu/.ssh/id_* w,

# Deny systemd and cron modifications
deny /etc/systemd/** w,
deny /var/spool/cron/** w,
deny /etc/cron.*/** w,

# Allow network except metadata endpoint
network inet stream,
network inet6 stream,
deny network inet to 169.254.169.254,

The pg_dump Incident

Three days into complain mode, database backups stopped working. The error was cryptic:

pg_dump: error: could not load library

The AppArmor logs showed denials for /usr/share/perl5/** and /usr/share/postgresql-common/**.

Here's what I learned: pg_dump isn't a compiled binary. It's a Perl wrapper that dynamically loads modules from /usr/share/perl5 and PostgreSQL-specific libraries from /usr/share/postgresql-common.

The lesson: trace the full execution chain. Don't just check the binary you're calling — check what it calls. Use strace if you need to:

$ strace -f pg_dump mydb 2>&1 | grep -i 'open|access' | less

Once I added read access to those paths, backups worked fine.

Tools for Profile Development

AppArmor ships with aa-logprof — an interactive tool that reads logs and suggests profile updates. It's helpful for initial development but you still need to review every suggestion. Don't blindly accept rules.

$ sudo aa-logprof

For syntax checking:

$ sudo apparmor_parser -r /etc/apparmor.d/your.profile

To switch a profile between modes:

$ sudo aa-complain /etc/apparmor.d/your.profile  # complain mode
$ sudo aa-enforce /etc/apparmor.d/your.profile   # enforce mode

Limitations

AppArmor is path-based. If your agent can write to /tmp, it can create /tmp/evil.sh and execute it (assuming execute permissions are granted).

SELinux (the alternative on RedHat/CentOS) is label-based and more granular, but also significantly more complex to configure. For most deployments, AppArmor's path-based model is easier to reason about and sufficient.

macOS: Santa + TCC

Most developers run macOS. If you're building AI agents locally before deploying to Linux, you need confinement on your development machine too.

macOS has two complementary systems:

Santa: Binary Authorization

Santa is Google's open-source binary authorization system for macOS. It operates at the kernel level via an Endpoint Security extension and controls whether executables can run.

You define rules based on:

  • Certificate: Allow/block all binaries signed by a specific developer certificate
  • Binary hash: Allow/block a specific executable (SHA-256)
  • Path: Allow/block based on file location

Santa runs in two modes:

  • Monitor mode: Logs execution events but doesn't block
  • Lockdown mode: Default-deny — only explicitly allowed binaries can execute

Example workflow for confining an AI agent:

  1. Run Santa in monitor mode for a week
  2. Review logs to see what the agent executes: santactl log
  3. Create allowlist rules for legitimate tools (git, npm, python, etc.)
  4. Switch to lockdown mode

Santa won't stop the AI agent from reading ~/.ssh/id_rsa, but it will stop it from executing an unsigned binary it downloads or compiles.

Installation:

$ brew install --cask santa
$ sudo santactl rule --allow --certificate --identifier "Developer ID Application: GitHub"

TCC: Transparency, Consent, and Control

TCC is macOS's built-in permission system for sensitive resources:

  • Camera and microphone
  • Full Disk Access
  • Files and Folders (Desktop, Documents, Downloads)
  • Automation (AppleScript, UI scripting)
  • Accessibility

By default, apps prompt the user for these permissions. You've seen the dialogs.

For enterprises, TCC can be pre-configured via MDM (Jamf, Kandji, SimpleMDM). You deploy profiles that grant or deny permissions without user prompts.

Example TCC profile (simplified) to deny Full Disk Access to a specific app:

<dict>
  <key>Services</key>
  <dict>
    <key>SystemPolicyAllFiles</key>
    <dict>
      <key>Allowed</key>
      <false/>
      <key>BundleIdentifier>
      <string>com.example.aiagent</string>
    </dict>
  </dict>
</dict>

Together, Santa and TCC give you application-level confinement similar to AppArmor:

  • Santa controls what can execute
  • TCC controls what executing processes can access

Limitations

TCC is app-based. If your AI agent runs as a shell script or Python process, TCC sees it as Terminal.app or Python.app — not as a distinct entity. You'd need to bundle the agent as a proper macOS application to get per-agent TCC enforcement.

Santa is stronger here — you can write rules based on executable hash or path, which works for scripts.

Windows: WDAC + AppLocker + Sandbox

Windows has the most mature enterprise confinement tooling, but also the most complex deployment model.

WDAC: Windows Defender Application Control

WDAC (formerly Device Guard) is Microsoft's code integrity policy engine. It operates at the kernel level and enforces digital signature requirements for executables, DLLs, and drivers.

Policies define:

  • Which signers are trusted (Microsoft, specific publishers)
  • File hash allowlists/blocklists
  • Path-based rules (less secure, but sometimes necessary)

WDAC is the strongest Windows confinement mechanism — it can block unsigned code even from local administrators. But it's also the hardest to deploy. Get the policy wrong and you'll break Windows Update, drivers, or line-of-business apps.

Deployment process:

  1. Audit mode: Deploy a policy that logs violations without blocking
  2. Review logs: Check Event Viewer → Applications and Services Logs → Microsoft → Windows → CodeIntegrity → Operational
  3. Refine policy: Add allowed signers and file hashes
  4. Enforce mode: Deploy enforcing policy via Group Policy or Intune

Example policy (simplified) to allow only Microsoft-signed binaries and block everything else:

<Signers>
  <Signer Name="Microsoft Windows" ID="ID_SIGNER_MICROSOFT">
    <CertRoot Type="Wellknown" Value="06" />
  </Signer>
</Signers>
<SigningScenarios>
  <SigningScenario Value="131" ID="ID_SIGNINGSCENARIO_WINDOWS">
    <ProductSigners>
      <AllowedSigners>
        <AllowedSigner SignerId="ID_SIGNER_MICROSOFT" />
      </AllowedSigners>
    </ProductSigners>
  </SigningScenario>
</SigningScenarios>

For AI agents: If your agent downloads Python scripts or compiles code on the fly, WDAC will block execution unless you add file hash rules or signer rules for the tools it uses (Python, Node.js, etc.).

AppLocker: Application Allowlisting

AppLocker is the lighter-weight alternative to WDAC. It's easier to deploy and understand, but also easier to bypass.

AppLocker rules control:

  • Executable files (.exe, .com)
  • Scripts (.ps1, .bat, .vbs, .js)
  • Windows Installer files (.msi, .msp)
  • DLLs
  • Packaged apps (UWP)

You configure rules via Group Policy or PowerShell. Example rule to block all scripts except those in C:ApprovedScripts:

New-AppLockerPolicy -RuleType Script -User Everyone `
  -RuleNamePrefix "Allow Approved Scripts" `
  -Path "C:ApprovedScripts*" -Action Allow | Set-AppLockerPolicy -Merge

AppLocker is appropriate for environments that need basic confinement without the complexity of WDAC. But it won't stop code injection or DLL hijacking — WDAC is required for kernel-level enforcement.

Windows Sandbox: Throwaway Environments

Windows Sandbox is a lightweight VM built into Windows 10/11 Pro and Enterprise. When you close it, everything inside is destroyed.

Use case for AI agents: Run untrusted agent-generated code inside Sandbox. If it tries to modify the registry, install persistence, or exfiltrate data, it's contained. Close the window, everything's gone.

Enable it:

Enable-WindowsOptionalFeature -FeatureName "Containers-DisposableClientVM" -All -Online

Launch:

WindowsSandbox.exe

You can pre-configure Sandbox environments via .wsb config files — mount specific folders as read-only, map network drives, run startup scripts.

Example config to mount a workspace folder as read-only:

<Configuration>
  <MappedFolders>
    <MappedFolder>
      <HostFolder>C:UsersYourNameProjects</HostFolder>
      <ReadOnly>true</ReadOnly>
    </MappedFolder>
  </MappedFolders>
</Configuration>

Deployment: Group Policy vs Intune

For on-prem Active Directory environments: Use Group Policy to deploy WDAC policies and AppLocker rules. Policies apply at computer or user scope.

For cloud-managed or hybrid environments: Use Microsoft Intune to deploy policies as device configuration profiles. Intune also supports compliance checks — you can require that devices have WDAC enabled before allowing access to corporate resources.

Implementation Pattern: Start in Audit Mode, Always

Across all three platforms, the pattern is the same:

  1. Deploy in audit/complain mode. Log violations without blocking.
  2. Run for 1-2 weeks. Let the agent do everything it normally does.
  3. Review every log. Understand what the agent actually accesses.
  4. Refine the policy. Add necessary allowances, remove overly broad rules.
  5. Test enforcement on a non-production system.
  6. Deploy enforcement. Monitor for breakage in the first 48 hours.

Do not skip the audit phase. You will miss something. And finding out in enforce mode means downtime.

Lessons Learned From Our Deployment

1. Trace the Full Execution Chain

Don't just profile the top-level command. Trace what it calls. pg_dump is a Perl script. Python apps import C libraries. Shell scripts exec other scripts. Use strace (Linux), dtruss (macOS), or Process Monitor (Windows) to see the full picture.

2. Logs Are Your Ground Truth

You don't know what the agent needs until you see what it tries to access. We ran complain mode for 2+ weeks specifically to catch edge cases — backups that run weekly, cron jobs that run monthly, API integrations that only trigger under certain conditions.

3. Read-Only Is Better Than No Access

Our profile allows the agent to read SSH public keys but not write private keys. It can read systemd unit files but not modify them. That's enough for most legitimate operations (checking git remote URLs, inspecting service status) while preventing the worst-case scenarios.

4. Network Rules Matter

Block access to the EC2 metadata endpoint (169.254.169.254). That endpoint returns IAM role credentials. If an attacker compromises the agent via prompt injection, you don't want them stealing the instance role token via SSRF.

5. Test Backups and Cron Jobs

These are the things you'll miss during development. Database backups broke because of Perl library access. Cron jobs failed because we initially denied write access to /tmp (which cron uses for lock files). Run the full operational cycle in complain mode before enforcing.

What This Doesn't Solve

Confinement is not a silver bullet. It won't stop:

  • Data exfiltration via allowed network routes. If the agent can write to ~/.openclaw/workspace and commit to git, it can exfiltrate data via git push. You need egress filtering and git hook validation for that.
  • Social engineering. If the agent can send emails or Slack messages (and mine can), it can phish users. Confinement limits file and process access, not communication channels.
  • Logic bugs in your own code. If your application has an RCE vulnerability, confinement limits the blast radius but doesn't prevent exploitation.

Confinement is one layer. You still need secrets management, egress controls, monitoring, and code review.

You Should Do This Now

If you're running AI agents with access to production systems and you haven't implemented confinement, you're running a non-deterministic process with excessive privileges. The question isn't whether something will go wrong — it's whether you'll contain it when it does.

Start with audit mode. You don't need to block anything yet. Just see what the agent accesses. Run it for a week. Then decide whether you're comfortable with that access profile.

If you're not sure where to start or you need help mapping this to your compliance framework (SOC 2, ISO 27001, NIST), that's what I do. Book a strategy session and we'll walk through your architecture.

If you found this useful, connect with me on LinkedIn where I write about AI security, compliance automation, and building systems that don't break. I'm also on Twitter/X for shorter takes and industry commentary.

AI securityAppArmorSantaWDACmandatory access controlAI agentsLinux securitymacOS securityWindows security

Ready to Assess Your Security?

Take our free 2-minute compliance checklist to see where you stand with SOC 2, HIPAA, and more.