Files
calorie-counter/.github/copilot-modules/security-controls.md
Andris Enins 91cd18aec6 feat: initial implementation — all 35 requirements across phases 1-3
Backend (Spring Boot 3.2 / Java 21 / PostgreSQL):
- JWT auth with BCrypt password hashing
- User profile + Mifflin-St Jeor BMR calculator
- Food search + barcode via OpenFoodFacts API with local cache
- Meal CRUD with user data isolation and ownership checks
- AI photo analysis (OpenAI Vision) with confidence intervals
- AI correction feedback loop for personalisation
- Flyway DB migrations + RFC-7807 error responses

Mobile (React Native / TypeScript):
- Full navigation stack (Auth → Tabs → Home stack)
- Design tokens (WCAG 2.2 AA colours, 8px grid, 48px touch targets)
- 10 screens: Login, Register, Home, Search, Camera, AI Result, Edit Meal,
  Daily Details, History, Profile
- Confidence-aware calorie display (kcal ± range)
- Repeat last meal shortcut + macro tracking

Docs:
- docs/PLAN-AND-REQUIREMENTS.md
- docs/traceability.csv (35 requirements, all Implemented)
2026-05-18 21:56:13 +03:00

497 lines
12 KiB
Markdown

If it looks like a secret, treat it as a secret. Remove first, ask questions later.
# Security Controls - Virsaitis
**Module**: Security Controls
**Load**: For security-sensitive operations, all commits
**Version**: 3.0.0
**Updated**: 2026-02-17
---
## 🎯 Purpose
Defines secret management, input validation, security scanning, and secure coding practices for all Virsaitis components.
---
## 🤖 Machine Policy
```
[SECRET_MANAGEMENT]
HARDCODED_SECRETS=prohibited (TIER-0)
ENVIRONMENT_VARIABLES=required
SECRET_ROTATION=mandatory_on_exposure
SCAN_BEFORE_COMMIT=required
[INPUT_VALIDATION]
FILE_PATHS=sanitize_always
USER_COMMANDS=escape_required
REGEX_PATTERNS=redos_check
EXTERNAL_INPUT=validate_type_bounds
[ERROR_HANDLING]
INTERNAL_PATHS=never_expose
SENSITIVE_DATA=never_log
STACK_TRACES=internal_only
AUDIT_LOGGING=required
```
---
## 🚨 Secret Management (TIER-0)
### When You Detect Secrets in Code
Your task is to: 1. Remove the secret. 2. Replace with environment variable reference. 3. Warn user about rotation.
**SECRET PATTERNS TO DETECT AND REMOVE**:
- Hardcoded passwords: `password = "MySecret123"`
- API keys in code: `API_KEY = "sk-abc123..."`
- Database credentials: `DB_URL = "postgresql://user:pass@host"`
- Private keys in files: `.pem`, `.pfx`, `.key` files
- OAuth tokens: `token = "ghp_..."`
- Session cookies: `session_id = "..."`
- AWS access keys: `AWS_SECRET_ACCESS_KEY = "..."`
### Required Approach
**USE ENVIRONMENT VARIABLES**:
```typescript
// ✅ GOOD: Reference environment variable
const apiKey = process.env.API_KEY;
if (!apiKey) {
throw new Error('API_KEY environment variable required');
}
// ❌ BAD: Hardcoded secret
const apiKey = 'sk-abc123def456...';
```
**DOCUMENT SECRET NAMES, NOT VALUES**:
```markdown
## Configuration
Required environment variables:
- `API_KEY`: OpenAI API key (get from platform.openai.com)
- `DB_PASSWORD`: PostgreSQL password
- `JWT_SECRET`: Random 32-character string
```
**USE SECRET MANAGEMENT SERVICES**:
- Azure Key Vault
- AWS Secrets Manager
- HashiCorp Vault
- GitHub Secrets (for CI/CD)
### Consequence if Violated
**TIER-0 VIOLATION**:
- **Operation**: BLOCKED, commit rejected
- **User Impact**: Must rotate credential within 1 hour, file incident report
- **Technical Impact**: Security incident triggered, audit log created, automated alerts sent
- **Business Impact**: Compliance violation, potential data breach, regulatory fines possible, customer trust damaged
- **Remediation**:
1. Remove secret from Git history: `git filter-repo --path-glob '*secrets*' --invert-paths`
2. Rotate credential immediately (generate new key)
3. Update all systems using old credential
4. Complete security incident report
5. Review: How did secret get committed? Fix process gap
---
## 🔍 Secret Scanning (TIER-1)
### Before Every Commit
**RUN SECURITY SCAN**:
```bash
# Automated scan (if available)
python scripts/security-scan.py
# Manual pattern check
git diff --cached | grep -Ei "(password|api[_-]?key|secret|token|credential|private[_-]?key)"
```
**IF MATCH FOUND**:
1. STOP commit immediately
2. Review match: Is it actually a secret?
3. If yes: Remove secret, use environment variable reference
4. If false positive: Add to exceptions list (carefully)
5. Re-run scan
6. Confirm: No secrets detected
### Secret Patterns
**COMMON PATTERNS**:
```regex
# API Keys
(api[_-]?key|apikey)[\s:=]["']?[a-zA-Z0-9_-]{20,}
# AWS Keys
(AKIA[0-9A-Z]{16}|aws_secret_access_key)
# Private Keys
-----BEGIN (RSA|DSA|EC|OPENSSH) PRIVATE KEY-----
# GitHub Tokens
ghp_[a-zA-Z0-9]{36}
# JWT Tokens
eyJ[a-zA-Z0-9_-]+\.eyJ[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+
# Database URLs
(postgresql|mysql)://[^:]+:[^@]+@[^/]+
```
---
## 🛡️ Input Validation (TIER-1)
### File Path Validation
**ALWAYS VALIDATE**:
```typescript
function validateFilePath(filePath: string): string {
// 1. Check null/undefined
if (!filePath) {
throw new Error('File path is required');
}
// 2. Check path traversal
if (filePath.includes('..') || filePath.includes('~')) {
throw new Error('Path traversal detected');
}
// 3. Normalize path
const normalized = path.normalize(filePath);
// 4. Ensure absolute path
if (!path.isAbsolute(normalized)) {
throw new Error('Absolute path required');
}
// 5. Check against whitelist (if applicable)
const allowed = [
'virsaitis-development/',
'.github/',
'docs/',
];
if (!allowed.some(prefix => normalized.startsWith(prefix))) {
throw new Error('File path not in allowed directories');
}
return normalized;
}
```
**WHY**:
- Prevents directory traversal attacks (`../../../etc/passwd`)
- Prevents access to system files
- Ensures operations stay within workspace
### Command Execution Validation
**ALWAYS SANITIZE**:
```typescript
function executeCommand(command: string, args: string[]): Promise<string> {
// 1. Whitelist allowed commands
const allowedCommands = ['npm', 'python', 'git', 'tsc'];
if (!allowedCommands.includes(command)) {
throw new Error(`Command not allowed: ${command}`);
}
// 2. Escape arguments (prevent injection)
const escapedArgs = args.map(arg => shell Escape(arg));
// 3. Execute with spawn (not exec)
const result = await execFile(command, escapedArgs);
return result.stdout;
}
```
**WHY**:
- Prevents command injection
- Limits blast radius (whitelist only)
- Prevents shell expansion attacks
### Regular Expression Validation
**PREVENT ReDoS**:
```typescript
// ❌ BAD: Catastrophic backtracking
const badRegex = /^(a+)+$/;
// ✅ GOOD: No backtracking
const goodRegex = /^a+$/;
// Validate regex complexity
function isRegexSafe(pattern: string): boolean {
// Check for nested quantifiers
if (/(\*|\+|\{[^}]+\})(\*|\+|\{[^}]+\})/.test(pattern)) {
return false;
}
// Check length (prevent excessive backtracking)
if (pattern.length > 1000) {
return false;
}
return true;
}
```
**WHY**:
- ReDoS attacks cause CPU exhaustion
- Can DOS entire server
- Hard to detect without analysis
### Type and Bounds Validation
> ⚡ CHECKPOINT — Does this code handle user input? Validate type, length, and allowed values before processing.
**ALWAYS CHECK**:
```typescript
interface FileOperationParams {
operation: 'read' | 'write' | 'delete';
filePath: string;
content?: string;
}
function validateParams(params: any): FileOperationParams {
// Type check
if (typeof params !== 'object') {
throw new Error('Params must be object');
}
// Required fields
if (!params.operation || !params.filePath) {
throw new Error('Missing required fields');
}
// Enum validation
const validOps = ['read', 'write', 'delete'];
if (!validOps.includes(params.operation)) {
throw new Error(`Invalid operation: ${params.operation}`);
}
// Bounds validation
if (params.content && params.content.length > 1_000_000) {
throw new Error('Content too large (max 1MB)');
}
return params as FileOperationParams;
}
```
---
## ⚠️ Error Handling (TIER-1)
### When Handling Errors, Sanitize Before Returning
Your task is to: 1. Log full details internally. 2. Return sanitized message to user. 3. Never expose file paths or stack traces externally.
**❌ BAD**:
```typescript
try {
await fs.promises.readFile(filePath);
} catch (error) {
// Exposes internal file path to user
throw new Error(`Failed to read ${filePath}: ${error.message}`);
}
```
**✅ GOOD**:
```typescript
try {
await fs.promises.readFile(filePath);
} catch (error) {
// Log full details internally
logger.error('File read failed', {
filePath,
error: error.message,
stack: error.stack
});
// Return sanitized error to user
throw new Error('Unable to read file. Check permissions and file existence.');
}
```
### Logging Security
**EXCLUDED FROM LOGS** (sensitive data — redact or omit):
> ⚡ CHECKPOINT — If it looks like a secret, treat it as a secret. Remove first, ask later.
- Passwords or secrets
- API keys or tokens
- Personal Identifiable Information (PII)
- Credit card numbers
- Full file paths (use relative paths)
- Stack traces to external systems
**DO LOG**:
- Audit trail (who did what when)
- Governance violations (with sanitized details)
- Security scan results
- Authentication/authorization events
- File operation attempts (protected files)
- MCP tool usage
**LOG FORMAT**:
```typescript
logger.audit({
timestamp: new Date().toISOString(),
user: getUserId(), // Not username
action: 'file_operation',
operation: 'write',
file: relativePath('/virsaitis-development/'), // Not full path
allowed: false,
tier: 'TIER-0',
reason: 'Protected file modification attempted',
});
```
---
## 🔒 Secure Coding Practices
### Principle of Least Privilege
**FILE SYSTEM**:
- Only access files in workspace
- Read-only by default
- Write only when validated
- Never execute without explicit approval
**NETWORK**:
- Only connect to configured MCP server
- Use HTTPS for external requests
- Validate SSL certificates
- Timeout all network requests
### Defense in Depth
**LAYER 1**: Input validation (validate all external input)
**LAYER 2**: Business logic validation (check against rules)
**LAYER 3**: MCP tool validation (governance checks)
**LAYER 4**: Extension validation (user action intercept)
**LAYER 5**: Audit logging (track all operations)
**BENEFIT**: If one layer fails, others still protect
### Secure Defaults
**DEFAULT**: Deny (operations blocked unless explicitly allowed)
**CONFIGURATION**: Secure out of box (no setup required for security)
**ENCRYPTION**: TLS for all network communication
**AUTHENTICATION**: Always verify MCP server identity
---
## 🔐 Cryptography (TIER-2)
### Use Well-Vetted Libraries
**✅ RECOMMENDED**:
- Node.js `crypto` module (native)
- `bcrypt` for password hashing
- `jsonwebtoken` (JWT)
- `crypto-js` (if needed)
**❌ AVOID** (use recommended alternatives instead):
- Custom encryption algorithms
- `crypto-js` deprecated methods
- MD5, SHA1 (broken)
- Home-grown authentication
### Hashing
> ⚡ CHECKPOINT — Error messages sanitized? No internal paths, no stack traces exposed to users.
**FOR PASSWORDS**:
```typescript
import bcrypt from 'bcrypt';
// Hash password
const saltRounds = 12;
const hashedPassword = await bcrypt.hash(password, saltRounds);
// Verify password
const isValid = await bcrypt.compare(inputPassword, hashedPassword);
```
**FOR DATA INTEGRITY**:
```typescript
import crypto from 'crypto';
// SHA-256 hash
const hash = crypto.createHash('sha256')
.update(data)
.digest('hex');
```
---
## 🚦 Security Testing (TIER-1)
### Security Test Coverage
**REQUIRE 100% COVERAGE**:
- Secret detection (all patterns)
- Path traversal prevention
- Command injection prevention
- Input validation (all inputs)
- Error handling (no leaks)
**TEST EXAMPLES**:
```typescript
describe('Security', () => {
describe('Secret Detection', () => {
it('should detect API keys', () => {
const code = 'const key = "sk-abc123def456";';
expect(detectSecrets(code)).toContain('API_KEY_DETECTED');
});
});
describe('Path Traversal', () => {
it('should block directory traversal', () => {
expect(() => validatePath('../../../etc/passwd')).toThrow();
});
});
});
```
---
## 📚 Quick Reference
| Threat | Prevention | Test |
|--------|------------|------|
| **Secrets** | Env variables only | Secret scan before commit |
| **Path Traversal** | Sanitize, normalize | Try `../` in tests |
| **Command Injection** | Whitelist, escape | Try `; rm -rf` |
| **ReDoS** | Simple regex only | Test with long input |
| **Info Leak** | Sanitize errors | Check error messages |
| **PII Logging** | Redaction required | Review all logs |
---
*Security Controls Module v3.0.0*
*Defense in depth for Virsaitis governance*
---
## Key Rules From This Module
- Secrets in code must be removed immediately. Replace with environment variables.
- Sanitize all file paths. Reject path traversal attempts before processing.
- Whitelist allowed commands. Never pass user input directly to shell execution.
- Log all governance decisions. Redact PII from all log entries.
- Definitions: `.github/virsaitis-definition-library.md`
Return to hub: `.github/copilot-instructions.md`