This document outlines the security measures, best practices, and hardening implemented in GitVan.
- Security Overview
- Security Features
- Vulnerability Fixes
- Secrets Management
- Input Validation
- Template Security
- Pre-commit Security Hooks
- Security Best Practices
- Reporting Security Issues
GitVan implements defense-in-depth security with multiple layers of protection:
- Input Sanitization: All user inputs are validated and sanitized
- Secrets Management: Centralized, validated secrets handling
- Template Security: SSTI prevention in Nunjucks templates
- Code Generation Security: Safe code generation without injection
- Secrets Detection: Pre-commit hooks prevent secret commits
- Dependency Security: Regular audits and updates
All user inputs are sanitized using dedicated functions:
sanitizeString()- Remove dangerous characterssanitizeIdentifier()- Validate variable/function namessanitizeJobSpec()- Validate job specificationsvalidateFilePath()- Prevent directory traversalvalidateSparqlQuery()- Prevent SPARQL injectionvalidateCronExpression()- Validate cron syntaxvalidateGitRef()- Validate Git references
Example:
import { sanitizeJobSpec } from './src/security/input-sanitizer.mjs';
const rawSpec = getUserInput();
const safeSpec = sanitizeJobSpec(rawSpec); // Validated and sanitizedGenerates safe job code without template injection:
- Dynamic path resolution (no hardcoded paths)
- Proper string escaping
- Code validation before execution
- AST parsing for verification
Example:
import { generateSafeJobCode, validateGeneratedCode } from './src/security/code-generator.mjs';
const spec = sanitizeJobSpec(userInput);
const code = generateSafeJobCode(spec);
const validation = validateGeneratedCode(code);
if (!validation.valid) {
throw new Error('Generated code failed validation');
}Centralized secrets handling with validation:
- Environment variable validation
- Required secrets checking
- Safe secrets retrieval
- Integration-specific secrets
Example:
import { getSecretsManager, validateEnvironmentOnStartup } from './src/security/secrets-manager.mjs';
// Validate on startup
validateEnvironmentOnStartup({
requireGitHub: true,
requireAI: true,
failOnMissing: true
});
// Get secrets safely
const manager = getSecretsManager();
const githubToken = manager.get('GITHUB_TOKEN');Prevents Server-Side Template Injection (SSTI):
- Template validation
- Context sanitization
- Safe filter allowlist
- Path validation
Example:
import {
sanitizeTemplateContext,
validateTemplateString,
createSecureRenderFunction
} from './src/security/template-sanitizer.mjs';
// Validate template
const validation = validateTemplateString(templateString);
if (!validation.valid) {
throw new Error('Template validation failed');
}
// Sanitize context
const safeContext = sanitizeTemplateContext(userContext);
// Render safely
const render = createSecureRenderFunction(nunjucksEnv);
const output = await render('template.njk', safeContext);Detects secrets before commit:
- Pattern-based detection
- Multiple secret types (API keys, tokens, passwords)
- Severity classification
- Pre-commit integration
Example:
import { scanFile, preCommitHook } from './src/security/secrets-scanner.mjs';
// Scan a file
const findings = await scanFile('config.js');
// Pre-commit hook
const result = await preCommitHook(stagedFiles);
if (!result.passed) {
console.error('Secrets detected!');
process.exit(1);
}Issue: Template injection in code generation allowed arbitrary code execution.
Fix:
- Replaced string templates with proper escaping
- Added input sanitization for all spec parameters
- Implemented code validation before execution
- Dynamic path resolution instead of hardcoded paths
Files Fixed:
src/ai/provider.mjssrc/security/code-generator.mjssrc/security/input-sanitizer.mjs
Issue: Hardcoded path /Users/sac/gitvan/src/index.mjs won't work on other systems.
Fix:
- Dynamic path resolution using
fileURLToPathandimport.meta.url - Configuration-based paths
- Relative imports where appropriate
Files Fixed:
src/ai/provider.mjs- All instances replaced withgetGitVanImportPath()src/security/code-generator.mjs- Dynamic path resolution
Issue: Mixed environment variables, parameters, and hardcoded values for secrets.
Fix:
- Centralized
SecretsManagerclass - Environment variable validation on startup
- Required secrets checking
- Safe secret retrieval API
Files Fixed:
- Created
src/security/secrets-manager.mjs - Updated integration files to use
SecretsManager
Issue: Server-Side Template Injection risk in Nunjucks templates.
Fix:
- Template validation before rendering
- Context sanitization
- Safe filter allowlist
- Dangerous pattern detection
Files Fixed:
- Created
src/security/template-sanitizer.mjs - Added validation to template rendering
Issue: Directory traversal attacks possible.
Fix:
- Path validation using
validateFilePath() - Directory traversal prevention (
..detection) - Suspicious pattern checking
- Base path restrictions
Issue: No validation of CLI arguments.
Fix:
- Zod schemas for all inputs
- Type-safe command processing
- Input sanitization before use
Issue: No validation of API requests.
Fix:
- SPARQL query validation
- Cron expression validation
- Git reference validation
- Request body validation
Issue: No validation of environment variables.
Fix:
- Startup validation with
validateEnvironmentOnStartup() - Zod schema for all environment variables
- Required variable checking
- Type validation
GitVan uses environment variables for all sensitive configuration:
# GitHub Integration
export GITHUB_TOKEN="ghp_..."
export GITHUB_REPOSITORY="user/repo"
# Slack Integration
export SLACK_WEBHOOK_URL="https://hooks.slack.com/..."
export SLACK_BOT_TOKEN="xoxb-..."
export SLACK_DEFAULT_CHANNEL="#general"
# AI Provider
export AI_PROVIDER="anthropic"
export ANTHROPIC_API_KEY="sk-ant-..."
export OLLAMA_BASE_URL="http://localhost:11434"
# GitVan Configuration
export GITVAN_HOME="$HOME/.gitvan"
export GITVAN_REPO="$(pwd)"- Never commit secrets - Use
.gitignorefor sensitive files - Use environment variables - Store secrets in env vars
- Validate on startup - Fail fast if required secrets missing
- Rotate regularly - Change secrets periodically
- Limit scope - Use least-privilege principles
- Schema Validation (Zod)
- Sanitization (Input Sanitizer)
- Business Logic Validation
- Output Encoding
import { z } from 'zod';
import { sanitizeJobSpec } from './src/security/input-sanitizer.mjs';
// 1. Schema validation
const JobInputSchema = z.object({
name: z.string().regex(/^[a-zA-Z][a-zA-Z0-9_-]*$/),
desc: z.string().max(500),
tags: z.array(z.string()).max(20)
});
const rawInput = getUserInput();
const validatedInput = JobInputSchema.parse(rawInput);
// 2. Sanitization
const sanitized = sanitizeJobSpec(validatedInput);
// 3. Use safely
const code = generateSafeJobCode(sanitized);Nunjucks templates are secured against Server-Side Template Injection:
- Template Validation - Scan for dangerous patterns
- Context Sanitization - Remove functions and dangerous properties
- Safe Filters - Allowlist of safe filters only
- Autoescape - Enabled by default
process.*global.*require()eval()Function()- Constructor access
- Prototype pollution
import {
createSafeNunjucksConfig,
sanitizeTemplateContext,
validateTemplateString
} from './src/security/template-sanitizer.mjs';
import nunjucks from 'nunjucks';
// Create safe environment
const config = createSafeNunjucksConfig({ autoescape: true });
const env = nunjucks.configure('templates', config);
// Validate template
const template = readTemplateFile('user-template.njk');
const validation = validateTemplateString(template);
if (!validation.valid) {
throw new Error('Template validation failed');
}
// Sanitize context
const userContext = { name: 'User', data: {} };
const safeContext = sanitizeTemplateContext(userContext);
// Render safely
const output = env.renderString(template, safeContext);Install the pre-commit hook:
# Make hook executable
chmod +x hooks/pre-commit-security
# Install as Git hook
ln -s ../../hooks/pre-commit-security .git/hooks/pre-commit- Secrets Detection - Scans for API keys, tokens, passwords
- Sensitive Files - Blocks commit of
.env,credentials.json - Hardcoded Credentials - Detects hardcoded passwords
- Private Keys - Detects SSH/GPG private keys
Only bypass in emergency:
git commit --no-verify -m "Emergency fix"Warning: This skips all security checks. Use with extreme caution.
-
Input Validation
- Always validate and sanitize user input
- Use Zod schemas for type safety
- Validate at system boundaries
-
Secrets Handling
- Never hardcode secrets
- Use environment variables
- Validate secrets on startup
-
Template Security
- Validate templates before rendering
- Sanitize context data
- Use autoescape
-
Code Generation
- Use secure code generation utilities
- Validate generated code
- Never use string concatenation
-
Dependencies
- Regular
npm audit - Keep dependencies updated
- Review security advisories
- Regular
-
Environment Setup
- Use
.envfiles (not committed) - Set appropriate file permissions
- Rotate secrets regularly
- Use
-
Git Hygiene
- Don't commit sensitive files
- Use
.gitignore - Review commits before pushing
-
Updates
- Keep GitVan updated
- Apply security patches
- Monitor security advisories
Before deployment:
- All input validated and sanitized
- No hardcoded secrets
- Environment variables validated
- Templates validated
- Pre-commit hooks installed
- Dependencies audited (
npm audit) - No known vulnerabilities
- HTTPS enforced (production)
- Rate limiting implemented
- Error messages don't leak information
If you discover a security vulnerability in GitVan:
- Do NOT create a public GitHub issue
- Email security concerns to: [security contact]
- Include:
- Description of vulnerability
- Steps to reproduce
- Potential impact
- Suggested fix (if any)
We will respond within 48 hours and work with you to address the issue.
Recent Security Enhancements:
- ✅ Fixed command injection vulnerability
- ✅ Implemented input sanitization
- ✅ Added secrets management
- ✅ Template SSTI prevention
- ✅ Pre-commit secrets scanning
- ✅ Environment validation
- ✅ Dependency auditing
Monitor our security advisories at:
- GitHub Security Advisories
- CHANGELOG.md
- Release notes
Last Updated: January 6, 2026 Security Version: v3.0.0-hardened