Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: rammie/rsh
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 0.0.4
Choose a base ref
...
head repository: rammie/rsh
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 0.0.5
Choose a head ref
  • 11 commits
  • 12 files changed
  • 2 contributors

Commits on Mar 25, 2026

  1. Fix sandbox escape via post-expansion absolute paths and harden edge …

    …cases
    
    - Executor's check_expanded_arg_path now rejects absolute paths (critical:
      command substitution like `cat $(realpath file)` could read arbitrary files)
    - Block sed -i/--in-place via PREFIX_BLOCKED when sed is added to allowlist
    - Glob expansion skips paths that fail canonicalize() instead of including them
    - Tilde expansion rejected in executor as defense-in-depth (validator already blocks)
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
    rammie and claude committed Mar 25, 2026
    Configuration menu
    Copy the full SHA
    bc9dee5 View commit details
    Browse the repository at this point in the history
  2. Extract shared check_arg_path_safety to deduplicate path checks

    The validator and executor had near-identical path safety checks
    (absolute path + traversal rejection). Unified into a single pub
    function in validator.rs that both call sites now use.
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
    rammie and claude committed Mar 25, 2026
    Configuration menu
    Copy the full SHA
    9fe8c29 View commit details
    Browse the repository at this point in the history
  3. Validate parameter expansion sub-expressions and implement &> redirects

    Fix critical security issue: command substitutions inside parameter
    expansion sub-expressions (e.g., ${var:-$(cmd)}, ${var:+$(cmd)},
    ${var/$(cmd)/repl}) were not validated, allowing arbitrary command
    execution bypassing the allowlist. The validator now parses and validates
    all sub-expression strings (default values, alternative values, error
    messages, patterns, replacements, array indices) for command
    substitutions and variable references.
    
    Also implement &> and &>> redirect execution (previously passed
    validation but was silently ignored), and document symlink traversal
    as a non-goal.
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
    rammie and claude committed Mar 25, 2026
    Configuration menu
    Copy the full SHA
    bd43e88 View commit details
    Browse the repository at this point in the history
  4. Harden validator: path-check redirects, cap for-loops, validate subst…

    …ring exprs, reject ${:=}
    
    Four security hardening fixes:
    - Validator now calls check_arg_path() on redirect target filenames, catching
      absolute paths and .. traversal before any process spawns (executor had this
      as defense-in-depth, but validator should enforce it too)
    - For-loop iterations capped at 10,000 (matching while/until loops)
    - ${var:offset:length} offset/length arithmetic expressions now validated for
      command substitutions and variable references
    - ${var:=default} (AssignDefaultValues) rejected as variable assignment
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
    rammie and claude committed Mar 25, 2026
    Configuration menu
    Copy the full SHA
    9120b9f View commit details
    Browse the repository at this point in the history
  5. Hard-block awk/sed, validate arithmetic expressions, track $? exit st…

    …atus, extract loop constant
    
    - Add ALWAYS_BLOCKED list: awk/gawk/mawk/nawk/sed/gsed are rejected even with
      --allow, since their built-in commands (system(), e, r, w) bypass rsh's
      security model. Remove sed from PREFIX_BLOCKED (now fully hard-blocked).
    - Validate arithmetic expressions ($((expr))) for embedded command substitutions
    - Track $? (last exit status) in local_vars so conditionals like
      `false || echo $?` work correctly
    - Extract MAX_LOOP_ITERATIONS constant shared by for/while/until loops
    - Update docs and tests
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
    rammie and claude committed Mar 25, 2026
    Configuration menu
    Copy the full SHA
    042d19d View commit details
    Browse the repository at this point in the history
  6. Fix concatenated short-flag path bypass, remove less from allowlist, …

    …execute stderr redirects in pipelines
    
    - Harden check_arg_path_safety to inspect values concatenated after short
      flag letters (e.g., -f../../secret), closing an information disclosure
      vector via grep -f, rg -f, file -f, etc.
    - Remove less from default allowlist — its interactive escape capabilities
      (pipe to commands, open editor) are unsafe; still available via --allow.
    - Execute stderr redirects (2>/dev/null, 2>&1) on non-final pipeline
      commands instead of silently ignoring them.
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
    rammie and claude committed Mar 25, 2026
    Configuration menu
    Copy the full SHA
    bc04bb6 View commit details
    Browse the repository at this point in the history
  7. Fix blocked-flag bypass via expansion, hard-block shells/interpreters…

    …/env/xargs
    
    Critical fix: blocked flags (find -delete/-exec, sort -o, fd --exec) could be
    injected via command substitution (e.g., `find . $(echo -delete)`) or for-loop
    variables, bypassing validation-time checks. The executor now re-checks blocked
    flags on expanded args and re-validates the expanded command name against the
    allowlist and ALWAYS_BLOCKED.
    
    - Add check_blocked_flags() and check_command_allowed() as shared public
      functions used by both validator and executor (deduplicated from prior
      private methods)
    - Hard-block shells (sh, bash, zsh, dash, ksh, csh, tcsh, fish), subprocess
      launchers (env, xargs), and interpreters (python, python3, perl, ruby, node)
      even with --allow
    - Add 17 new tests covering expansion bypass vectors and hard-blocked commands
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
    rammie and claude committed Mar 25, 2026
    Configuration menu
    Copy the full SHA
    bf65c96 View commit details
    Browse the repository at this point in the history

Commits on Mar 26, 2026

  1. Move path checking from validator to executor, making executor the se…

    …curity boundary
    
    The validator now does structural AST checks only (allowlist, blocked flags,
    forbidden syntax, variable approval, redirect gating). All path checking
    (absolute paths, .. traversal) happens post-expansion in the executor, where
    it operates on actual expanded strings rather than raw Word.value text.
    
    This eliminates a long tail of edge cases from trying to statically analyze
    bash's dynamic string construction (parameter expansion variants, command
    substitution output, etc.). The executor already re-validates command names,
    blocked flags, and argument paths after expansion — this change makes that
    the single source of truth for value-based security checks.
    
    Changes:
    - validator: remove check_arg_path calls (args, for-loop values, redirects)
    - executor: add validate_redirect_target helper for post-expansion path checks
    - executor: reject unsupported parameter expansions instead of silent empty string
    - executor: add ParameterLength support, remove redundant absolute path check
      from apply_redirects
    - docs: update CLAUDE.md and README.md to explain validator vs executor roles
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
    rammie and claude committed Mar 26, 2026
    Configuration menu
    Copy the full SHA
    114f842 View commit details
    Browse the repository at this point in the history
  2. Pin allowlist at compile time, remove --allow flag and ALWAYS_BLOCKED

    The --allow flag, RSH_ALLOWLIST env var, and ~/.rsh/allowlist config file
    created a whack-a-mole problem: any binary that can exec (shells, scripting
    languages, xargs, env, etc.) had to be individually blocklisted. Instead,
    pin the allowlist at compile time so only explicitly listed commands can
    run — no runtime override possible.
    
    - Remove --allow CLI flag, RSH_ALLOWLIST env var, ~/.rsh/allowlist config
    - Remove ALWAYS_BLOCKED list (no longer needed without --allow)
    - Simplify Allowlist::load(cli_allow) to Allowlist::new()
    - Add printf and printenv to pinned allowlist (read-only, useful for testing)
    - Consolidate duplicate "not in allowlist" tests with shared helper
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
    rammie and claude committed Mar 26, 2026
    Configuration menu
    Copy the full SHA
    0813ecb View commit details
    Browse the repository at this point in the history
  3. Fix blocked-flag bypass via combined short-flag clusters (fd -Hx, sor…

    …t -ro)
    
    Single-letter blocked flags like fd's -x/-X and sort's -o could be hidden
    inside combined short-flag clusters (e.g., -Hx, -ro, -nro) which bypassed
    both exact-match and prefix-match checks. fd -Hx is particularly critical
    since fd's -x spawns arbitrary commands outside rsh's sandbox.
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
    rammie and claude committed Mar 26, 2026
    Configuration menu
    Copy the full SHA
    1045483 View commit details
    Browse the repository at this point in the history
  4. Add built-in restricted sed for safe line extraction

    Implement sed as an in-process builtin that only supports -n with
    address+p (e.g. sed -n '10,20p' file). No sed binary is executed,
    eliminating the risk of sed's e (execute), w (write), s///e, and -i
    features. Supports single lines, ranges, $ (last line), multiple
    expressions via semicolons or -e, multiple files, and stdin pipelines.
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
    rammie and claude committed Mar 26, 2026
    Configuration menu
    Copy the full SHA
    dd89ce3 View commit details
    Browse the repository at this point in the history
Loading