Skip to content

Escape values in --dry-run curl preview to prevent shell injection - #1

Open
brodkin wants to merge 1 commit into
egnyte:masterfrom
brodkin:fix/dry-run-shell-escaping
Open

Escape values in --dry-run curl preview to prevent shell injection#1
brodkin wants to merge 1 commit into
egnyte:masterfrom
brodkin:fix/dry-run-shell-escaping

Conversation

@brodkin

@brodkin brodkin commented Jul 23, 2026

Copy link
Copy Markdown

Summary

--dry-run prints a curl command for the user to inspect and copy. That command is built by concatenating the request URL and JSON body inside single quotes without escaping (formatDryRun in src/lib/output.js). A value that contains a single quote ends the quoted string. Egnyte paths can contain apostrophes, semicolons, and other shell metacharacters, and path validation in src/lib/validation.js does not reject them, so a path can both break the previewed command and inject additional shell commands into output the user is likely to paste into a terminal.

Reproduction

$ egnyte fs delete "/Shared/x'; touch /tmp/pwned ;'" --dry-run
curl -X DELETE 'https://<domain>/pubapi/v1/fs/Shared/x'; touch /tmp/pwned ;'' \
  -H 'Authorization: ***'

The single quote after x closes the quoted argument, so ; touch /tmp/pwned ; runs as a separate command if the previewed line is pasted into a shell. This is reachable from every command that previews through formatDryRun, including fs delete, fs action, fs move, fs copy, fs rename, fs mkdir, fs upload, fs set-metadata, and request. This matters most for a tool driven by AI agents over folder names an outside party can set, where the --dry-run preview is the human review step before execution.

Fix

Add shellQuote() and use it for the URL, the JSON body, and the multipart file argument. The same input is then emitted as a single safe argument:

curl -X DELETE 'https://<domain>/pubapi/v1/fs/Shared/x'\''; touch /tmp/pwned ;'\''' \
  -H 'Authorization: ***'

The Authorization: *** masking is unchanged.

Note

The chunked-upload preview in src/commands/fs.js builds its own curl lines with double-quoted interpolation and has the same class of issue. I scoped this PR to the shared formatDryRun path. I am happy to extend it to the chunked preview here or in a follow-up, whichever you prefer.

The --dry-run preview built its curl command by concatenating the URL and
JSON body inside single quotes without escaping. A value containing a
single quote, such as an Egnyte path with an apostrophe, terminated the
quoted string and produced a syntactically broken command. A crafted path
could also inject additional shell commands into the previewed output,
which a user is invited to copy and run.

Add shellQuote() and use it for the URL, JSON body, and multipart file
argument so interpolated values are always safely quoted.
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.

1 participant