Skip to content

Fix unsafe shell invocation in amber exec#1376

Merged
crimson-knight merged 1 commit into
amberframework:masterfrom
tcoatswo:fix/amber-cli-injection-complete
Jun 11, 2026
Merged

Fix unsafe shell invocation in amber exec#1376
crimson-knight merged 1 commit into
amberframework:masterfrom
tcoatswo:fix/amber-cli-injection-complete

Conversation

@tcoatswo

@tcoatswo tcoatswo commented May 19, 2026

Copy link
Copy Markdown

Summary

Replace shell-interpolated process execution in amber exec with argument-array Process.run calls.

Changes

  • replace shell-based editor launch with direct process execution
  • replace shell-based file copy with direct process execution
  • add regression coverage for shell metacharacters in --editor and copied filenames

Verification

I could not run the Crystal spec suite in this environment because the host does not have crystal or shards installed. This PR includes regression specs for the affected code paths for maintainers/CI to exercise.

crimson-knight added a commit to amberframework/amber_cli that referenced this pull request Jun 10, 2026
…22)

* Harden editor invocation against shell injection; fix Crystal 1.20 deprecations

exec.cr and encrypt.cr previously called system("#{editor} #{filename}"),
allowing shell metacharacters in the EDITOR env var or filename to execute
arbitrary commands. Replace with Process.parse_arguments + Process.run so
the editor string is word-split (supporting "code -w", "vim -u none", etc.)
and the filename is passed as a literal argument with no shell involvement.
Add regression specs asserting shell metacharacters in editor/filename do
not execute.

Fix pattern contributed by @tcoatswo in amberframework/amber#1376.

process_runner.cr used Time.monotonic which is deprecated in Crystal 1.20.0
in favour of Time.instant (Time::Instant, introduced in 1.20.0). Replace
both call sites. The shard.yml crystal floor is raised to >= 1.20.0 to
match (see version bump commit).

Fix contributed by @renich in amberframework/amber#1379.

amber.js Channel.join/leave/push previously called this.socket.ws.send()
without error handling; a dead WebSocket throws an uncaught DOMException in
the browser. Wrap each send in try/catch with a fallback to _reconnect().

Fix pattern contributed by @jonsilverman50-star in amberframework/amber#1375.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Bump version to 2.0.1; raise Crystal floor to >= 1.20.0

Time.instant (used in process_runner.cr) was introduced in Crystal 1.20.0.
Raise the shard.yml crystal constraint from >= 1.10.0 to >= 1.20.0 to
reflect this requirement. Bump shard version 2.0.0 -> 2.0.1 to signal the
patch release containing the exec/encrypt hardening and deprecation fixes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
@crimson-knight

Copy link
Copy Markdown
Member

Thank you for tracking down both injection vectors and writing regression specs to cover them. Replacing the shell-interpolated system() calls with argument-array Process invocations is exactly the right fix — shell metacharacters in editor names or filenames are a real attack surface.

Both PRs are valid and complementary (#1376 → master, #1377 → stable backport). Merging both.

You'll also want to know your fix outlived v1: the standalone CLI that replaces the bundled one had independently fixed the file-copy path with FileUtils.cp, but the editor-launch injection was still there. It's now hardened in amber_cli#22 — using Process.parse_arguments so multi-word editors like code -w still work — with credit to this PR, and shipped in v2.0.1.

Maintainer attention has been on V2 (now public: #1383), which is why these sat for a few weeks — sorry about that, and grateful for the security work.

@crimson-knight crimson-knight merged commit 0715387 into amberframework:master Jun 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants