Ecosystem

escapes

Setuid-root Rust binary for local privilege elevation via AuthZ-JWT.

escapes

A setuid-root Rust binary that executes commands with elevated privileges after verifying an AuthZ-JWT from an OpenApe IdP. It replaces traditional sudo with grant-based, auditable approval.

escapes runs with root privileges. Follow the security hardening guidelines at the bottom of this page.

Installation

# Build from source
cd escapes
cargo build --release

# Install with setuid bit
sudo make install  # → /usr/local/bin/escapes

The make install target:

  • Copies the binary to /usr/local/bin/escapes
  • Sets ownership to root:root
  • Enables the setuid bit (chmod u+s)

Usage

escapes receives a pre-approved AuthZ-JWT (typically from grapes) and executes the authorized command.

Grant Delivery Methods

# JWT as command-line argument
escapes --grant <jwt> -- systemctl restart nginx

# JWT from stdin (pipe-friendly)
echo "$JWT" | escapes --grant-stdin -- apt-get upgrade

# JWT from file
escapes --grant-file /tmp/grant.jwt -- systemctl restart nginx

# Run as specific user (instead of root)
escapes --run-as deploy --grant <jwt> -- systemctl restart nginx

Typical Flow with grapes

# One-liner: request, wait, execute
grapes run escapes "systemctl restart nginx" --reason "Deploy"

# Manual flow
grapes request "apt-get upgrade" --audience escapes --wait
JWT=$(grapes token <grant-id>)
escapes --grant "$JWT" -- apt-get upgrade

Verification Chain

Before executing any command, escapes performs a 7-step verification:

  1. Issuer check — JWT issuer matches a configured allowed issuer
  2. Signature verification — JWT signature is valid (EdDSA)
  3. Approver checkdecided_by claim is in the allowed approvers list
  4. Audience checkaud claim matches "escapes" (or configured audience)
  5. Target host checktarget_host claim matches the current hostname
  6. Command hash checkcmd_hash matches the SHA-256 hash of the command to execute
  7. IdP consume check — For once grants, calls the IdP's /consume endpoint to mark the grant as used

If any check fails, execution is aborted with exit code 5.

Configuration

Config file location: /etc/openape/config.toml (root-owned, mode 0644)

# Optional: override system hostname
host = "prod-server.example.com"

# User to run commands as (default: root)
run_as = "root"

# Audit log location
audit_log = "/var/log/openape/audit.log"

[security]
# Only accept JWTs from these issuers
allowed_issuers = ["https://id.example.com"]

# Only accept approvals from these users
allowed_approvers = ["admin@example.com", "ops@example.com"]

# Only accept JWTs with these audiences
allowed_audiences = ["escapes"]

[tls]
# Custom CA bundle for IdP verification
ca_bundle = "/etc/ssl/certs/ca-certificates.crt"

Audit Logging

Every execution attempt is logged as JSONL to the audit log:

{
  "timestamp": "2025-01-15T10:30:00Z",
  "grant_id": "abc123-...",
  "command": ["systemctl", "restart", "nginx"],
  "requester": "agent+deploy@example.com",
  "approver": "admin@example.com",
  "result": "success",
  "exit_code": 0,
  "duration_ms": 1234
}

Failed attempts (verification failures, execution errors) are also logged:

{
  "timestamp": "2025-01-15T10:31:00Z",
  "error": "cmd_hash mismatch",
  "expected_hash": "sha256:a1b2c3...",
  "actual_hash": "sha256:d4e5f6...",
  "command": ["rm", "-rf", "/"],
  "requester": "agent+deploy@example.com"
}

Exit Codes

CodeMeaning
0Command executed successfully
1Configuration error or HTTP error (IdP unreachable)
5JWT verification failed (any of the 7 checks)
126Command found but execution failed (permission denied)
127Command not found

Environment Sanitization

Before executing the command, escapes resets the environment to prevent privilege escalation attacks:

  • LD_PRELOAD, LD_LIBRARY_PATH — removed
  • PATH — reset to safe default (/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin)
  • All other environment variables — removed except explicitly safe ones

Security Hardening

Mandatory

  • Config file must be owned by root with restricted permissions
  • allowed_issuers should list only your IdP(s) — never use wildcards
  • allowed_approvers should list only trusted human administrators
  • Audit log directory must be writable by root only
  • Enable DNSSEC for your IdP domain
  • Use a dedicated agent user per machine (not a shared key)
  • Monitor the audit log for failed verification attempts
  • Rotate agent Ed25519 keys periodically
  • Use once grants for destructive operations; reserve always grants for read-only actions