mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-10-27 12:12:49 +00:00
ci: the ui helpers check wait times are numbers, and the Claude guard refuses unquoted glob, brace and tilde, so no file name a session creates can run a command
The guard checks the command text before the Bash tool's shell expands it, and the session can create files with any name in its working directory. So `ui wait x S*`, with a file named `SECONDS[$(…)]` beside it, passed the guard, and the iOS and desktop helpers put the expanded name into `$((SECONDS + …))`, where bash runs the subscript's command substitution, in a process whose ancestors' environment holds the Claude token. Android's helper already checked the number.
Now the desktop helper checks `wait` and `click-text` seconds as Android's does, the iOS helper checks them in `wait_for`, and both guards refuse `*?[]{}~` outside quotes (the plans quote all text, and inside quotes these don't expand).
This commit is contained in:
1 parent
2f40c0ee12
commit
c229dcd2ca
4 files changed
+19
-4
No files matched your search
@@ -11,12 +11,18 @@ import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
# nothing that chains, pipes, redirects, substitutes, expands or escapes
|
||||
# nothing that chains, pipes, redirects, substitutes, expands with $ or escapes
|
||||
UI_COMMAND = re.compile(r"ui( [^;&|<>$`()\\\r\n]*)?")
|
||||
# and, outside quotes, no glob, brace or tilde expansion, which could turn names of files the session creates into
|
||||
# arguments; QUOTED finds the shell's quotes only because UI_COMMAND refuses backslashes
|
||||
UNQUOTED_EXPANSION = re.compile(r"[*?\[\]{}~]")
|
||||
QUOTED = re.compile(r"\"[^\"]*\"|'[^']*'")
|
||||
|
||||
call = json.load(sys.stdin)
|
||||
command = (call.get("tool_input") or {}).get("command", "").strip()
|
||||
allowed = call.get("tool_name") != "Bash" or UI_COMMAND.fullmatch(command)
|
||||
allowed = call.get("tool_name") != "Bash" or (
|
||||
UI_COMMAND.fullmatch(command) and not UNQUOTED_EXPANSION.search(QUOTED.sub("", command))
|
||||
)
|
||||
if os.environ.get("CLAUDE_GUARD_LOG"):
|
||||
with open(os.environ["CLAUDE_GUARD_LOG"], "a") as log:
|
||||
log.write(f"{'allow' if allowed else 'refuse'} {call.get('tool_name')}: {command[:200]!r}\n")
|
||||
|
||||
@@ -236,6 +236,7 @@ case "${1:-}" in
|
||||
;;
|
||||
wait)
|
||||
secs=${3:-30}
|
||||
number "$secs"
|
||||
if ! pos=$(wait_for "$2" "$secs"); then
|
||||
log "wait \"$2\": not on screen after $secs s"
|
||||
exit 1
|
||||
@@ -253,6 +254,7 @@ case "${1:-}" in
|
||||
;;
|
||||
click-text)
|
||||
secs=${3:-20}
|
||||
number "$secs"
|
||||
if ! pos=$(wait_for "$2" "$secs"); then
|
||||
log "click-text \"$2\": not on screen after $secs s"
|
||||
exit 1
|
||||
|
||||
@@ -11,12 +11,18 @@ import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
# nothing that chains, pipes, redirects, substitutes, expands or escapes
|
||||
# nothing that chains, pipes, redirects, substitutes, expands with $ or escapes
|
||||
UI_COMMAND = re.compile(r"ui( [^;&|<>$`()\\\r\n]*)?")
|
||||
# and, outside quotes, no glob, brace or tilde expansion, which could turn names of files the session creates into
|
||||
# arguments; QUOTED finds the shell's quotes only because UI_COMMAND refuses backslashes
|
||||
UNQUOTED_EXPANSION = re.compile(r"[*?\[\]{}~]")
|
||||
QUOTED = re.compile(r"\"[^\"]*\"|'[^']*'")
|
||||
|
||||
call = json.load(sys.stdin)
|
||||
command = (call.get("tool_input") or {}).get("command", "").strip()
|
||||
allowed = call.get("tool_name") != "Bash" or UI_COMMAND.fullmatch(command)
|
||||
allowed = call.get("tool_name") != "Bash" or (
|
||||
UI_COMMAND.fullmatch(command) and not UNQUOTED_EXPANSION.search(QUOTED.sub("", command))
|
||||
)
|
||||
if os.environ.get("CLAUDE_GUARD_LOG"):
|
||||
with open(os.environ["CLAUDE_GUARD_LOG"], "a") as log:
|
||||
log.write(f"{'allow' if allowed else 'refuse'} {call.get('tool_name')}: {command[:200]!r}\n")
|
||||
|
||||
@@ -71,6 +71,7 @@ point() {
|
||||
|
||||
wait_for() {
|
||||
local text=$1 secs=${2:-30}
|
||||
number "$secs"
|
||||
local deadline=$((SECONDS + secs)) t
|
||||
until t=$(tree 2> /dev/null) && grep -qF -- "$text" <<< "$t"; do
|
||||
if [ "$SECONDS" -ge "$deadline" ]; then
|
||||
|
||||
Reference in new issue
Block a user