Skip to content

Latest commit

 

History

History
122 lines (91 loc) · 4 KB

File metadata and controls

122 lines (91 loc) · 4 KB

Interpreter Usage

Guide for running language interpreters through Terminal's command filter.

Critical: Terminal validates the command string, not what the command does. Any allowed interpreter can execute arbitrary code via script files.

The StrictArgs Challenge

With strictArgs: true (default), shell metacharacters including parentheses () are blocked. This affects inline code execution:

// BLOCKED - Parentheses detected as shell metacharacters
await Terminal.execute('python3 -c print(42)')
await Terminal.execute('deno eval console.log(42)')
await Terminal.execute('node -e console.log(42)')

Error: Argument validation failed: Invalid characters in argument 1: shell metacharacters detected

Solution 1: Disable Strict Validation (Less Secure)

For trusted environments only:

Terminal.initialize({
  workspaces: ['/safe/project'],
  commands: {
    allow: ['deno', 'python3', 'node'],
    deny: ['sudo'],
    maxArgs: 20,
    strictArgs: false, // Allow () for function calls
    noShell: true
  }
})

// Now works
await Terminal.execute('python3 -c print(42)')

Warning

Security Risk: Disables protection against shell injection. Only use in controlled environments.

Solution 2: File-Based Execution

Write code to file first, then execute:

const scriptPath = '/safe/project/script.py'
await Deno.writeTextFile(scriptPath, `print("hello")`)
const result = await Terminal.execute(`python3 ${scriptPath}`)

Caution

Terminal does NOT inspect file contents. A script file can contain os.system('rm -rf /') and Terminal will pass it through. File-based execution requires OS-level hardening:

  • Run as unprivileged user
  • Use filesystem permissions (chmod 600)
  • Consider chroot or containers
  • Pre-approve script files, do not let AI write them

Solution 3: Pre-Installed Scripts (Safest)

For common operations, prepare and audit scripts in advance. Do not let AI agents write script files dynamically.

// Script is pre-audited and immutable
const result = await Terminal.execute('python3 /safe/project/scripts/check-version.py')

Command Parser Behavior

Terminal's parser splits commands on whitespace only:

Input Parsed As Note
echo a b c ['echo', 'a', 'b', 'c'] ✅ Works
echo a,b,c ['echo', 'a,b,c'] ✅ Comma stays in arg
cmd; rm / ['cmd;', 'rm', '/'] ; is part of arg 0
a && b ['a', '&&', 'b'] && becomes arg 1

Shell operators do NOT work (even with strictArgs: false):

// Parsed as separate args, NOT chained commands
await Terminal.execute('deno eval console.log(1), console.log(2)')
// Args: ['deno', 'eval', 'console.log(1),', 'console.log(2)']

Complete Example (with OS hardening)

import Terminal from '@neabyte/terminal'

Terminal.initialize({
  workspaces: ['/workspace'],
  commands: {
    allow: ['python3 /workspace/preinstalled/*.py'],
    deny: ['sudo'],
    maxArgs: 5,
    strictArgs: true,
    noShell: true
  },
  timeout: 10000
})

// Only execute pre-audited scripts
const result = await Terminal.execute('python3 /workspace/preinstalled/hello.py arg1 arg2')
console.log(result.stdout)

Best Practices

  1. Never allow node, python3, deno with wildcard patterns - node /workspace/*.js is a sandbox bypass
  2. Always use noShell: true - Prevents shell interpretation
  3. Pre-install scripts, never generate them at runtime - Terminal does not inspect file contents
  4. Combine with OS hardening - See Security for chroot, containers, seccomp
  5. Run as unprivileged user - Never run Terminal as root

See Also