T09 · Insecure Skill Coding Practices
- Location
SKILL.md:46- Finding
JQ Expression Injection Can Disconnect Unrelated Agents
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md, lines 46–47 and 73–74
Vulnerability Type: JQ expression injection caused by unsafe string interpolation
Risk Level: HighVulnerable Code
bash pilotctl --json connections | jq -r '.connections[] | select(.remote_hostname == "'"$AGENT"'") | .id' | \ xargs -I {} pilotctl --json disconnect {}The same vulnerable command also appears in the quarantine enforcement workflow at lines 73–74.
Technical Analysis
The
AGENTvariable is inserted directly into the jq program rather than being supplied as a jq data argument. Consequently, quotes and jq operators in an agent name are interpreted as executable jq syntax.For example, an agent value resembling:
text " or true or .remote_hostname == "can change the selection condition so that it evaluates as true for every connection. All matching connection IDs are then passed directly to the state-changing
pilotctl disconnectcommand.Shell quoting does not protect the jq expression because the shell deliberately terminates the single-quoted jq program to interpolate
AGENT.Attack Path
- An attacker registers, advertises, or provides a crafted agent hostname containing jq syntax.
- An operator copies that value into the documented
AGENTvariable or stores it in a quarantine record. - The quarantine or enforcement workflow inserts the value into the jq program.
- The injected predicate selects connections other than the intended agent.
xargsinvokespilotctl --json disconnectfor each selected connection.- Legitimate agents are disconnected from the Pilot Protocol network.
Impact Assessment
Exploitation grants no additional operating-system privileges, but it allows an attacker to misuse all connection-management authority available to the invoking
pilotctluser. The scope can include every connection returned bypilotctl --json connections, resul ...[truncated 78 chars]- Remediation
View remediation
Remediation Suggestions
Pass the agent name as data through jq's
--argoption instead of constructing jq source code:bash pilotctl --json connections | jq -r --arg agent "$AGENT" \ '.connections[] | select(.remote_hostname == $agent) | .id' | xargs -r -I {} pilotctl --json disconnect -- {}Apply the same correction to lines 73–74. In addition:
- Validate agent hostnames against the Pilot Protocol's documented hostname syntax.
- Reject control characters, quotes, and unexpected whitespace where they are not valid hostname characters.
- Verify that
pilotctl findreturns exactly one valid node before changing trust. - Preview or count selected connection IDs before disconnecting them.
- Use
xargs -rso no command is executed when the input is empty.
