MCPcopy Index your code
hub / github.com/codeaashu/claude-code / isCommandReadOnly

Function isCommandReadOnly

src/tools/BashTool/readOnlyValidation.ts:1678–1752  ·  view source on GitHub ↗

* Checks if a single command string is read-only based on READONLY_COMMAND_REGEXES. * Internal helper function that validates individual commands. * * @param command The command string to check * @returns true if the command is read-only

(command: string)

Source from the content-addressed store, hash-verified

1676 * @returns true if the command is read-only
1677 */
1678function isCommandReadOnly(command: string): boolean {
1679 // Handle common stderr-to-stdout redirection pattern
1680 // This handles both "command 2>&1" at the end of a full command
1681 // and "command 2>&1" as part of a pipeline component
1682 let testCommand = command.trim()
1683 if (testCommand.endsWith(' 2>&1')) {
1684 // Remove the stderr redirection for pattern matching
1685 testCommand = testCommand.slice(0, -5).trim()
1686 }
1687
1688 // Check for Windows UNC paths that could be vulnerable to WebDAV attacks
1689 // Do this early to prevent any command with UNC paths from being marked as read-only
1690 if (containsVulnerableUncPath(testCommand)) {
1691 return false
1692 }
1693
1694 // Check for unquoted glob characters and expandable `$` variables that could
1695 // bypass our regex-based security checks. We can't know what these expand to
1696 // at runtime, so we can't verify the command is read-only.
1697 //
1698 // Globs: `python *` could expand to `python --help` if such a file exists.
1699 //
1700 // Variables: `uniq --skip-chars=0$_` — bash expands `$_` at runtime to the
1701 // last arg of the previous command. With IFS word splitting, this smuggles
1702 // positional args past "flags-only" regexes like uniq's `\S+`. The `$` token
1703 // check inside isCommandSafeViaFlagParsing only covers COMMAND_ALLOWLIST
1704 // commands; hand-written regexes in READONLY_COMMAND_REGEXES (uniq, jq, cd)
1705 // have no such guard. See containsUnquotedExpansion for full analysis.
1706 if (containsUnquotedExpansion(testCommand)) {
1707 return false
1708 }
1709
1710 // Tools like git allow `--upload-pack=cmd` to be abbreviated as `--up=cmd`
1711 // Regex filters can be bypassed, so we use strict allowlist validation instead.
1712 // This requires defining a set of known safe flags. Claude can help with this,
1713 // but please look over it to ensure it didn't add any flags that allow file writes
1714 // code execution, or network requests.
1715 if (isCommandSafeViaFlagParsing(testCommand)) {
1716 return true
1717 }
1718
1719 for (const regex of READONLY_COMMAND_REGEXES) {
1720 if (regex.test(testCommand)) {
1721 // Prevent git commands with -c flag to avoid config options that can lead to code execution
1722 // The -c flag allows setting arbitrary git config values inline, including dangerous ones like
1723 // core.fsmonitor, diff.external, core.gitProxy, etc. that can execute arbitrary commands
1724 // Check for -c preceded by whitespace and followed by whitespace or equals
1725 // Using regex to catch spaces, tabs, and other whitespace (not part of other flags like --cached)
1726 if (testCommand.includes('git') && /\s-c[\s=]/.test(testCommand)) {
1727 return false
1728 }
1729
1730 // Prevent git commands with --exec-path flag to avoid path manipulation that can lead to code execution
1731 // The --exec-path flag allows overriding the directory where git looks for executables
1732 if (
1733 testCommand.includes('git') &&
1734 /\s--exec-path[\s=]/.test(testCommand)
1735 ) {

Callers 1

checkReadOnlyConstraintsFunction · 0.85

Calls 3

Tested by

no test coverage detected