T09 · Insecure Skill Coding Practices
- Location
core.mjs:109- Finding
Repository Visibility Guard Can Be Bypassed with Valid GitHub CLI Syntax
- Content
View full analysis
Vulnerability Details
File Location:
core.mjs:109-121; enforcement behavior inguard.mjs:46-49
Vulnerability Type: Incomplete security-command parsing
Risk Level: HighVulnerable Code
js export function parseVisibilityCommand(command) { // Match: gh repo edit <org/repo> ... --visibility public const editMatch = command.match(/gh\s+repo\s+edit\s+([^\s]+)/); if (!editMatch) return null; const visibilityMatch = command.match(/--visibility\s+(public|private|internal)/); if (!visibilityMatch || visibilityMatch[1] !== 'public') return null; const slug = editMatch[1]; const parts = slug.split('/'); if (parts.length !== 2) return null; return { org: parts[0], repo: parts[1], isVisibilityChange: true }; }The hook treats a parsing failure as an irrelevant command:
js // Only check commands that look like visibility changes const parsed = parseVisibilityCommand(command); if (!parsed) { process.exit(0); }Technical Analysis
The security control attempts to recognize visibility changes by applying regular expressions to an unparsed shell command. It only recognizes a narrow form resembling:
bash gh repo edit owner/repository --visibility publicThe expression for the visibility option requires whitespace between
--visibilityandpublic. GitHub CLI accepts the conventional equals-sign option form:bash gh repo edit owner/repository --visibility=publicThis form does not match
/--visibility\s+(public|private|internal)/, causingparseVisibilityCommand()to returnnull. The hook then exits successfully and does not return a denial.The parser also assumes that the first token after
gh repo editis an explicitowner/repositoryslug. Valid forms that operate on the repository in the current working directory, or other syntactically different invocations, are not reliably covered. Raw regular-expression ...[truncated 1460 chars]- Remediation
View remediation
Remediation Suggestions
- Do not use regular expressions over raw shell text as the primary security boundary.
- Prefer intercepting a structured tool invocation where the executable and argument array are provided separately.
- If Bash commands must be inspected, use a maintained shell parser and recursively inspect every command in pipelines, command substitutions, groups, and compound statements.
- Explicitly support both
--visibility publicand--visibility=public, arbitrary valid option ordering, quoted arguments, and invocations that infer the repository from the current working directory. - Resolve implicit repository targets before allowing a public visibility operation.
- Conservatively deny any
gh repo editcommand containing an ambiguous or unparseable visibility option. - Add regression tests for equivalent CLI forms, shell composition, aliases, quoting, omitted repository arguments, and malformed commands.
- Where possible, enforce the policy using GitHub organization rules or another server-side control, rather than relying exclusively on a client-side command hook.
