Safe-mode shell blocklist scans the entire command text (including here-doc payloads), causing false-positive blocks and non-uniform enforcement across safe_mode #114
Labels
No labels
auto/blocked-by-deps
auto/ci-timeout
auto/claimed-implementer
auto/claimed-merge
auto/claimed-reviewer
auto/driver-down
auto/invariant-violation
auto/last-attempt-tier-0
auto/last-attempt-tier-1
auto/last-attempt-tier-2
auto/last-attempt-tier-min
Automation Tracking
auto/needs-conflict-resolution
auto/needs-implementer
auto/postmortem
auto/ready-to-merge
auto/restart-throttled
auto/revert
auto/sentinel
auto/stale-inactivity
auto/unstable
Blocked
Bounty
$100
Bounty
$1000
Bounty
$10000
Bounty
$20
Bounty
$2000
Bounty
$250
Bounty
$50
Bounty
$500
Bounty
$5000
Bounty
$750
MoSCoW
Could have
MoSCoW
Must have
MoSCoW
Should have
Needs Feedback
Points
1
Points
13
Points
2
Points
21
Points
3
Points
34
Points
5
Points
55
Points
8
Points
88
Priority
Backlog
Priority
CI Blocker
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Signed-off: Owner
Signed-off: Scrum Master
Signed-off: Tech Lead
Spike
State
Completed
State
Duplicate
State
In Progress
State
In Review
State
Paused
State
Unverified
State
Verified
State
Wont Do
Type
Automation
Type
Bug
Type
Discussion
Type
Documentation
Type
Epic
Type
Feature
Type
Legendary
Type
Refactor
Type
Support
Type
Task
Type
Testing
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
cleveragents/cleveractors-core#114
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Metadata
Commit Message:
feat(agents): scope safe-mode shell blocklist to invocation regionsBranch:
feature/m3-shell-safe-mode-blocklist-matchingBackground and context
Actor Configuration Standard v1.1.0 (
docs/index.md) defines the safe-mode shellblocklist twice:
the literal substrings:
rm,del,format,shutdown,reboot,kill(case-insensitive comparison)."
regardless of mode."
cleveractors.agents.tool.ToolAgent._execute_shell_command(commit5520daf)implements this as a single check:
commandis the entire shell string passed to theshelltool, including anyhere-doc payload the command writes to disk. Since the check is a raw substring
scan over that whole string, it fires on ordinary English words and Python
identifiers that happen to contain a blocked token, with no relation to what the
shell will actually execute —
"del"⊂"deliberately","format"⊂"format_value"/format(...), etc.This was hit running
packages/calculator-app-actor.yaml(acalculator_builderLLM agent with
allow_shell: true,tools: [file_read, file_write, shell],writing a Python calculator app via
cat > file.py <<'PYEOF' ... PYEOFheredocs).Every attempt to write
commands.pyorengine.pywas rejected — not because theagent tried to run
rm/kill/etc., but because the file content being writtencontained the words "deliberately" and "format_value"/
format(...).Separately, the current
if self.safe_mode:gate means the blocklist is notenforced when
safe_mode: false, which contradicts §13.5's "MUST always beenforced regardless of mode." Code and spec disagree here, and per this
project's rule the spec is authoritative — the code is wrong on this point
independent of anything else in this issue.
Current behavior
commandstring passed to theshelltool, with no distinction between text that will be interpreted as shell
syntax and text that is inert payload (here-doc bodies, quoted string
literals, comments).
"perform", "skillful", etc. is blocked, even though none of it causes
rm,del,format,shutdown,reboot, orkillto execute.if self.safe_mode:, so it is skipped entirely when anagent has
safe_mode: false— contradicting §13.5's unconditionalenforcement requirement.
packages/calculator-app-actor.yaml; thecalculator_builderagent's
shellheredoc writes tocommands.py/engine.pyare repeatedlyrejected with
Dangerous command '...' blocked in safe mode, purely becausethe Python source/comments contain "deliberately" / "format_value".
Expected behavior
that the invoked shell will actually parse and execute as command syntax —
not to the contents of here-doc bodies, quoted string/text literals, or
comments that are opaque data as far as the shell is concerned.
above: it identifies actual command tokens (e.g. by tokenizing on shell
metacharacters/word boundaries) rather than raw substring containment across
arbitrary prose.
bodies" — it must also not be trivially defeated by shell-level obfuscation
that reassembles a blocked command at execution time (e.g. quoted/concatenated
fragments like
'r''m'orr\m, command substitution such as$(...)/backticks,
eval,bash -c "..."/sh -c "...", or piping through anotherinterpreter). The threat model is: block what would actually run, catch
attempts to smuggle a blocked command past the check, and stop flagging text
that never reaches the shell as a command.
safe_mode, per§13.5 — the
if self.safe_mode:gate around the check is removed (this doesnot relax anything else
safe_modecurrently governs, e.g.file_read/file_writeboundaries).and the "MUST always be enforced" applicability language of §13.5, it is an
architectural change to the standard, not a bug-in-code-vs-already-accepted-spec
fix. Per this project's ADR-before-code rule, it requires: extending
docs/adr/ADR-2030-tool-calling-spec-extensions.mdin place with a newdecision (next available slot: D-9) describing the parsing/matching design
and getting it accepted, then a spec revision to
docs/index.md§4.5.4.1/§13.5via the standard spec-revision procedure (bump the document Version, add a
§21.1 Revision History row attributing the change to the ADR) — before any
implementation code is merged.
Acceptance criteria
shellcall whose command line writes a here-doc/file payload containingthe words "deliberately", "format_value", or a call to
format(...)isnot blocked when the actual command being run is
cat > <file> <<'EOF'(or equivalent) and contains no invocation of a blocklisted command.
shellcall that actually invokesrm,del,format,shutdown,reboot, orkillas a command (including through common obfuscationsagreed in the ADR, e.g. quoted-fragment reassembly or
bash -c "...") isstill blocked.
safe_modeistrueorfalse(verifiable: a blocked command is rejected in bothconfigurations).
docs/adr/ADR-2030-tool-calling-spec-extensions.mdcontains an accepteddecision (D-9) describing the new matching design before the corresponding
code change is merged.
docs/index.md§4.5.4.1 and §13.5 reflect the new matching semantics, withthe document Version bumped and a §21.1 Revision History row attributing the
change to ADR-2030 D-9.
nox(all default sessions) is green andnox -s coverage_reportstays≥ 97%.
Supporting information
packages/calculator-app-actor.yaml):Tool execution failed: Dangerous command 'cat > calculator_app/calculator/commands.py <<'PYEOF' ... Undo/Memento is deliberately left out ... PYEOF' blocked in safe modeand the same pattern against
engine.pyfor text containingformat_value/format(...).docs/index.md§4.5.4.1 (shell blocklistdefinition) and §13.5 (unconditional enforcement requirement).
docs/adr/ADR-2030-tool-calling-spec-extensions.md— D-7 already coversshell/python_exectool registration and gating (allow_shell); this isthe natural home for the new decision (D-9) rather than a new ADR file.
5520daf:cleveractors.agents.tool.ToolAgent.__init__(setsself.safe_mode = cfg.get("safe_mode", True))cleveractors.agents.tool.ToolAgent._execute_shell_command(the blocklist check and theif self.safe_mode:gate)cleveractors.agents.tool.ToolAgent._shell_tool(passes the full command string into_execute_shell_command)allow_unsafeas used inpackages/calculator-app-actor.yamlis not arecognized config key anywhere in the spec or codebase (confirmed via
repo-wide search) and has no effect on this issue — unrelated to the fix.
Subtasks
ADR-2030-tool-calling-spec-extensions.mdin place with a new decision (D-9) proposing shell-invocation-region-scoped blocklist matching plus an anti-obfuscation approach; submit for review and get it accepted before writing codedocs/index.md§4.5.4.1 and §13.5 per the spec-revision procedure (bump Version, add a §21.1 Revision History row attributing to ADR-2030 D-9) — no inline edits without thisToolAgent._execute_shell_command(cleveractors.agents.tool)if self.safe_mode:gate so the blocklist check runs unconditionally, per §13.5rm,kill, etc. ARE blocked; blocklist enforced identically withsafe_mode: trueandsafe_mode: falseshelltool end-to-end with a here-doc file write followed by a chained dangerous commandnox -s coverage_reportnox(all default sessions), fix any errorsDefinition of Done
This issue is complete when:
docs/index.md§4.5.4.1/§13.5 are updated via the spec-revision procedure before implementation code is merged.