Multi-Provider Code Review implements security best practices:
- Secrets detection: Scans for 15+ types of hardcoded credentials
- Input validation: Prevents path traversal and injection attacks
- Budget limits: Prevents cost-based denial of service
- Secure dependencies: Regular security audits and updates
- Least privilege: Minimal GitHub token permissions required
The action automatically scans code changes for exposed credentials:
Detected secret types:
- AWS access keys and secret keys
- Google Cloud API keys and service account JSON
- Azure connection strings and client secrets
- Private keys (RSA, DSA, EC, OpenSSH, PGP)
- Slack tokens
- GitHub personal access tokens
- Generic API keys
- Database connection strings with credentials
- JWT tokens
- Payment provider keys (Stripe, PayPal)
- Communication service keys (Twilio, SendGrid, MailChimp)
- Hardcoded passwords
How it works:
// Findings are created with 'critical' severity
{
severity: 'critical',
title: 'Possible AWS access key',
message: 'Rotate the key immediately and remove it from source control.'
}Configuration:
- ENABLE_SECURITY: true # Enable secrets scanning (recommended: always true)Exclusions:
- Test files are automatically excluded
- Secrets in
__tests__/,*.test.ts,*.spec.jsare ignored - Pattern matches are case-sensitive for precision
All user inputs are validated to prevent security vulnerabilities:
Path Traversal Protection:
// Prevents: ../../etc/passwd
validateFilePath(filePath); // Throws if contains '..'
// Enhanced validation with base directory restriction
const safePath = validateFilePath(userPath, '/safe/base');
// Throws if resolved path escapes base directoryAPI Key Validation:
// Ensures API keys are properly formatted
validateApiKey(key, 'OpenAI'); // Checks length and formatConfiguration Validation:
// Validates all config before use
validateConfig(config);
// Checks: numeric bounds, enum values, array types, etc.Additional protections:
- PR numbers must be positive integers
- Timeouts must be reasonable (1s - 600s)
- Budget limits must be non-negative
- Model IDs must be properly formatted
- File paths checked for:
- Directory traversal (
..) - Control characters (0x00-0x1F)
- Double slashes (
//) - Suspicious patterns
- Directory traversal (
Prevent cost-based denial of service:
- BUDGET_MAX_USD: 0.50 # Hard limit per reviewHow it works:
- Checks cost before each provider execution
- Halts immediately when budget exceeded
- Returns partial results if budget hit mid-review
- Logs budget status to Action logs
Recommended limits:
- Development/staging: $0.10 - $0.50
- Production (routine): $0.50 - $1.00
- Production (critical): $1.00 - $5.00
All operations have timeout limits to prevent resource exhaustion:
- RUN_TIMEOUT_SECONDS: 300 # Total review timeout
- PROVIDER_TIMEOUT_MS: 30000 # Per-provider timeout
- GRAPH_TIMEOUT_SECONDS: 10 # Graph analysis timeoutBenefits:
- Prevents infinite loops in provider calls
- Limits resource consumption
- Ensures predictable execution time
- Gracefully handles hung providers
Built-in provider rate limiting:
// Automatic backoff on rate limit errors
if (response.status === 429) {
const retryAfter = response.headers['retry-after'];
await sleep(retryAfter * 1000);
// Retry with exponential backoff
}Configuration:
- PROVIDER_RETRIES: 3 # Max retry attempts
- PROVIDER_MAX_PARALLEL: 5 # Concurrent provider callsProtection against:
- API rate limit violations
- Provider billing overages
- Service degradation from excessive requests
Moderate severity (3 vulnerabilities):
- Package:
undici(HTTP client) - Issue: Unbounded decompression in HTTP responses
- Impact: Potential resource exhaustion (DoS)
- Affected: Transitive dependency via
@actions/github
Risk assessment:
- Low risk for typical usage
- Exploitable only through malicious HTTP responses
- GitHub Actions environment has resource limits
- Not exposed to user input
Remediation plan:
- Monitor for upstream fixes in
@actions/github - Apply security patches when available without breaking changes
- Regular
npm auditruns in CI/CD pipeline
Current practices:
- Regular dependency updates
- Automated security scanning
- Minimal dependency footprint
- Pin exact versions in package-lock.json
Dependencies reviewed:
@actions/github: GitHub API client (official)@octokit/rest: GitHub REST API (official)openai: OpenAI SDK (official)anthropic-sdk: Anthropic SDK (official)tree-sitter: Code parsing (widely used, audited)- All others: Standard utility libraries
Update policy:
- Security patches: Applied immediately
- Minor updates: Weekly review
- Major updates: Tested before deployment
- Breaking changes: Evaluated for impact
Minimal permissions needed:
permissions:
contents: read # Read repository code
pull-requests: write # Post review commentsNOT required:
contents: write- Action never modifies codeadmin- No administrative access neededsecrets- No access to repository secrets
-
Use built-in GITHUB_TOKEN:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- Automatically generated per workflow run
- Scoped to the repository
- Expires after workflow completes
-
Never use Personal Access Tokens (PAT) unless required:
- PATs have broader permissions
- Longer-lived than GITHUB_TOKEN
- Higher risk if exposed
-
For fork PRs, use pull_request_target carefully:
# Secure: Runs in base repo context with GITHUB_TOKEN on: pull_request_target:
- Be aware of security implications
- External contributors can't access secrets
- Consider using
SKIP_LABELSto exclude untrusted PRs
If GITHUB_TOKEN is compromised:
- GitHub automatically rotates on workflow completion
- No manual action required
- New token generated for next run
If PAT is used and compromised:
- Revoke immediately at https://github.com/settings/tokens
- Audit Actions logs for unauthorized access
- Generate new PAT with minimal permissions
- Update repository secrets
Always use repository secrets:
env:
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}Never:
- Hardcode API keys in workflow files
- Commit keys to repository
- Log keys in Action output
- Share keys across repositories (use organization secrets if needed)
Regular rotation schedule:
- Free tier keys: Quarterly
- Paid tier keys: Monthly
- After team member departure: Immediately
- After suspected compromise: Immediately
Rotation process:
- Generate new key from provider dashboard
- Update GitHub repository secret
- Revoke old key
- Verify workflow runs successfully
Limit key permissions:
- OpenRouter: No special scoping available
- OpenAI: Use project-scoped keys when possible
- Anthropic: Workspace-scoped keys recommended
- Custom providers: Use read-only keys if supported
Secure container configuration:
# Run as non-root user
USER node
# Drop unnecessary capabilities
RUN setcap cap_net_bind_service=+ep /usr/local/bin/node
# Read-only filesystem where possible
docker run --read-only --tmpfs /tmp multi-provider-reviewEnvironment variables:
# Use secrets management, not env files
docker run \
--env-file /dev/null \
-e GITHUB_TOKEN=$(vault read -field=token secret/github) \
-e OPENROUTER_API_KEY=$(vault read -field=key secret/openrouter) \
multi-provider-reviewFirewall rules:
# Allow outbound to provider APIs only
# GitHub API
iptables -A OUTPUT -d api.github.com -p tcp --dport 443 -j ACCEPT
# OpenRouter
iptables -A OUTPUT -d openrouter.ai -p tcp --dport 443 -j ACCEPT
# Deny all other outbound by default
iptables -P OUTPUT DROPTLS/SSL:
- All provider connections use HTTPS
- Certificate validation enabled by default
- No plaintext API communication
Webhook validation:
// Verify GitHub webhook signature
import { createHmac, timingSafeEqual } from 'crypto';
function verifyWebhook(payload: string, signature: string, secret: string): boolean {
const hmac = createHmac('sha256', secret);
hmac.update(payload);
const expectedSignature = hmac.digest('hex');
// Extract signature without "sha256=" prefix
const providedSignature = signature.startsWith('sha256=')
? signature.slice(7)
: signature;
// Convert to buffers for constant-time comparison
const expectedBuffer = Buffer.from(expectedSignature, 'hex');
const providedBuffer = Buffer.from(providedSignature, 'hex');
// If lengths differ, compare against zero-filled buffer to avoid timing leaks
if (expectedBuffer.length !== providedBuffer.length) {
const zeroBuffer = Buffer.alloc(expectedBuffer.length);
timingSafeEqual(expectedBuffer, zeroBuffer);
return false;
}
return timingSafeEqual(expectedBuffer, providedBuffer);
}Configuration:
# Set webhook secret in GitHub repository settings
# Use same secret in self-hosted deployment
WEBHOOK_SECRET: <strong-random-secret>Local data storage:
- Cache directory:
.mpr-cache/ - Contains: Previous review results, analytics data
- Does NOT contain: API keys, GitHub tokens, secrets
Sensitive data handling:
- Provider API responses: Not persisted to disk
- PR diffs: Cached temporarily, cleared on TTL expiration
- Findings: Stored without context code (only line numbers + messages)
Compliance:
- GDPR: No personal data collected
- SOC 2: Suitable for compliant deployments
- HIPAA: Not designed for healthcare data (requires additional controls)
If you discover a security vulnerability:
- DO NOT open a public GitHub issue
- DO email security report to maintainers
- DO include:
- Description of vulnerability
- Steps to reproduce
- Potential impact
- Suggested fix (if any)
- Acknowledgment: Within 48 hours
- Assessment: Within 1 week
- Fix: Critical issues within 2 weeks, others within 30 days
- Disclosure: Coordinated disclosure after fix is released
- Use
GITHUB_TOKEN, not Personal Access Token - Store provider API keys in repository secrets
- Enable secrets scanning (
ENABLE_SECURITY: true) - Set reasonable budget limits
- Review provider permissions and scopes
- Enable Dependabot for security updates
- Monitor Action logs for errors
- Rotate API keys regularly
- Run container as non-root user
- Use secrets management (Vault, AWS Secrets Manager)
- Configure firewall rules
- Enable webhook signature validation
- Set up TLS for webhook endpoints
- Monitor container logs for suspicious activity
- Implement log aggregation and alerting
- Regular security updates (OS, Node.js, dependencies)
- Backup and rotation of cache directory
- Network segmentation (DMZ for webhook server)
- Review provider responses for sensitive data leaks
- Don't trust LLM outputs blindly - validate suggestions
- Use incremental review to limit exposure of full codebase
- Skip untrusted PRs with
SKIP_LABELS - Monitor costs for unusual activity (potential abuse)
- Minimal provider set - only use what you need
- Conservative timeouts - prevent resource exhaustion
- Budget limits - protect against cost attacks
- Dry run mode - test config changes safely
- Audit logs - review Action logs regularly
- Principle of least privilege - minimal GitHub permissions
- Defense in depth - multiple security layers
- Regular updates - keep dependencies current
- Incident response plan - know what to do if compromised
- Security monitoring - alerts for anomalies
- GitHub Actions Security Hardening
- OWASP API Security Top 10
- CWE Top 25 Software Weaknesses
- NIST Cybersecurity Framework
- Error Handling Guide - Resilience and recovery
- Troubleshooting Guide - Common issues
- Self-Hosted Deployment - Production setup