ruvnet/ruflo · error
Invalid git ref: suspicious pattern
Error message
Invalid git ref: suspicious pattern
What it means
The second stage of validateGitRef(): the ref already passed the charset check but contains '..' and does not match the narrow range syntaxes the guard permits (side \w+\..[.\w]+ forms and simple A..B / A...B ranges of alphanumerics, underscores and hyphens). It exists to block path traversal and malformed range arguments before git is invoked.
Solutions
- Use short names for ranges: 'main..feature' or 'main...feature' (letters, digits, _ and - only on each side)
- Resolve each side to a full SHA with git rev-parse and pass 'SHA1..SHA2'
- Reject any ref containing '..' at your input boundary unless it matches /^\w+\.\.[.\w]+$/
- Never build refs from filesystem paths or free user text
Example fix
// before
const files = getGitDiffNumstat('refs/heads/main..refs/heads/feature'); // throws: suspicious pattern
// after
import { execSync } from 'node:child_process';
const a = execSync('git rev-parse --verify refs/heads/main').toString().trim();
const b = execSync('git rev-parse --verify refs/heads/feature').toString().trim();
const files = getGitDiffNumstat(`${a}..${b}`); // SHA..SHA passes Defensive patterns
Strategy: validation
Validate before calling
function isSafeRangeRef(ref: string): boolean {
if (!/^[a-zA-Z0-9_\-./~^@]+$/.test(ref)) return false;
if (ref.includes('..') && !/^\w+\.\.[.\w]+$/.test(ref)) return false;
return true;
} Type guard
function asRangeRef(a: string, b: string): string {
if (!/^\w+$/.test(a) || !/^\w+$/.test(b)) throw new Error('range sides must be plain names or SHAs');
return `${a}..${b}`;
} Try / catch
try {
files = getGitDiffNumstat(ref);
} catch (e) {
if (e instanceof Error && e.message.includes('suspicious pattern')) {
// rebuild the range from resolved SHAs and retry once
files = getGitDiffNumstat(`${shaA}..${shaB}`);
} else throw e;
} Prevention
- Build '..' ranges only from short branch names or 40-char SHAs — never from refs/heads/... full names
- Resolve both sides to SHAs before constructing range strings
- Reject any input containing '..' unless it matches the narrow range shape
When it happens
Trigger: Passing a range whose sides contain slashes, e.g. 'refs/heads/main..refs/heads/feature'; chained dots like 'a..b..c'; trailing/leading dots like 'main..'; a path-like string '..' or '../..' that got past the charset check; refspecs with '..' embedded in a longer path.
Common situations: Comparing full refnames (refs/heads/...) instead of short names; constructing ranges by string concatenation without validation; tools forwarding directory-ish user input into diff stats; traversal payloads aimed at the git subprocess.
Related errors
- Invalid git ref: contains unsafe characters
- Invalid git ref: too long
- registry path escapes owned worktree root
- basePath contains disallowed characters
- build input escapes repository
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/86893b0a56bbb3c5.
Report an issue: GitHub.
Appendix: source
Thrown at v3/@claude-flow/cli/src/ruvector/diff-classifier.ts:378
// ============================================================================
// Cache for diff results (TTL-based)
const diffCache = new Map<string, { files: DiffFile[]; timestamp: number }>();
const CACHE_TTL_MS = 5000; // 5 seconds - short TTL since diffs change frequently
/**
* Validate git ref to prevent command injection
* Only allows safe characters: alphanumeric, -, _, /, ., ~, ^
*/
function validateGitRef(ref: string): void {
// Block shell metacharacters and dangerous patterns
if (!/^[a-zA-Z0-9_\-./~^@]+$/.test(ref)) {
throw new Error(`Invalid git ref: contains unsafe characters`);
}
// Block multiple dots (path traversal)
if (ref.includes('..') && !ref.match(/^[a-zA-Z0-9_\-]+\.\.\.?[a-zA-Z0-9_\-]+$/)) {
if (!/^\w+\.\.[.\w]+$/.test(ref)) {
throw new Error(`Invalid git ref: suspicious pattern`);
}
}
// Max length check
if (ref.length > 256) {
throw new Error(`Invalid git ref: too long`);
}
}
/**
* Get git diff statistics using SINGLE combined command (optimized)
* Replaces two separate git commands with one
*/
export function getGitDiffNumstat(ref: string = 'HEAD'): DiffFile[] {
// SECURITY: Validate git ref to prevent command injection
validateGitRef(ref);
// Check cache first
const cacheKey = `numstat:${ref}`;View on GitHub (pinned to fa13ee4ad6)