| name | vigil-security-patterns |
| description | Security best practices and patterns for Vigil Guard v2.0.0 development. Use when implementing authentication, handling secrets, validating input, preventing injection attacks, managing CORS, ensuring secure coding practices, 3-branch detection security, or implementing security audit fixes. |
| version | 2.0.0 |
| allowed-tools | ["Read","Write","Edit","Bash","Grep","Glob"] |
Vigil Guard Security Patterns (v2.0.0)
Overview
Comprehensive security best practices for developing and maintaining Vigil Guard's security-critical codebase with 3-branch parallel detection architecture.
When to Use This Skill
- Implementing authentication flows
- Managing secrets and credentials
- Validating user input
- Preventing injection attacks
- Configuring CORS policies
- Handling password hashing
- Implementing RBAC permissions
- Secure session management
- Code review for security issues
- 3-branch service security (v2.0.0)
v2.0.0 Architecture Security
3-Branch Detection Security
11 Docker Services Security:
Core Services:
- clickhouse (data storage, port 8123)
- grafana (monitoring, port 3001)
- n8n (workflow engine, port 5678)
3-Branch Detection (v2.0.0):
- heuristics-service (Branch A, port 5005, 30% weight)
- semantic-service (Branch B, port 5006, 35% weight)
- prompt-guard-api (Branch C, port 8000, 35% weight)
PII Detection:
- presidio-pii-api (port 5001)
- language-detector (port 5002)
Web Interface:
- web-ui-backend (port 8787)
- web-ui-frontend (via proxy)
- proxy (Caddy, port 80)
Branch Service Security Considerations
Branch A (Heuristics - port 5005):
Risks:
- Pattern injection via crafted input
- DoS via complex regex (ReDoS)
- Config file manipulation
Mitigations:
- Pattern timeout limits (1000ms)
- unified_config.json validation
- Read-only config mount in Docker
Branch B (Semantic - port 5006):
Risks:
- Model poisoning (if model updates allowed)
- Embedding manipulation attacks
- Resource exhaustion (GPU/CPU)
Mitigations:
- Fixed model (all-MiniLM-L6-v2)
- Input
Arbiter v2 Security
const WEIGHTS = {
branch_a: 0.30,
branch_b: 0.35,
branch_c: 0.35
};
const THRESHOLDS = {
block: 70,
sanitize: 30,
allow: 0
};
function arbiterDecision(scores) {
const validBranches = Object.entries(scores)
.filter(([_, score]) => score !== null);
if (validBranches.length === 0) {
return { decision: 'BLOCK', reason: 'all_branches_degraded' };
}
const totalWeight = validBranches
.reduce((sum, [branch]) => sum + [branch], );
normalizedScore = validBranches
.(
sum + (score * [branch] / totalWeight), );
(normalizedScore);
}
Authentication Security
JWT Token Management
import jwt from 'jsonwebtoken';
const SECRET = process.env.JWT_SECRET;
const EXPIRY = '24h';
function generateToken(user: User): string {
return jwt.sign(
{
id: user.id,
username: user.username,
permissions: user.permissions,
iat: Math.floor(Date.now() / 1000)
},
SECRET,
{ expiresIn: EXPIRY }
);
}
function verifyToken(token: string): JwtPayload | null {
try {
return jwt.verify(token, SECRET) as JwtPayload;
} catch (error) {
if (error instanceof jwt.) {
.();
} (error jwt.) {
.();
}
;
}
}
Password Security
import bcrypt from 'bcrypt';
const SALT_ROUNDS = 12;
async function hashPassword(password: string): Promise<string> {
return await bcrypt.hash(password, SALT_ROUNDS);
}
async function verifyPassword(password: string, hash: string): Promise<boolean> {
return await bcrypt.compare(password, hash);
}
function validatePasswordStrength(password: string): boolean {
return password.length >= 8;
}
Permission Checks
function requirePermission(permission: string) {
return (req: Request, res: Response, next: NextFunction) => {
const user = req.user;
if (!user) {
return res.status(401).json({ error: 'Authentication required' });
}
if (!user.permissions.includes(permission)) {
return res.status(403).json({ error: 'Permission denied' });
}
next();
};
}
app.post('/api/config/:filename',
authMiddleware,
requirePermission('can_view_configuration'),
configHandler
);
Input Validation
Path Traversal Prevention
const ALLOWED_FILES = [
'unified_config.json',
'pii.conf',
'sections.json',
'variables.json'
];
function validateFilename(filename: string): boolean {
if (filename.includes('..') || filename.includes('/') || filename.includes('\\')) {
return false;
}
return ALLOWED_FILES.includes(filename);
}
SQL Injection Prevention
async function queryEvents(sessionId: string) {
const client = getClickHouseClient();
const query = `
SELECT
timestamp,
original_input,
final_status,
branch_a_score,
branch_b_score,
branch_c_score,
arbiter_decision
FROM n8n_logs.events_processed
WHERE sessionId = {sessionId:String}
ORDER BY timestamp DESC
LIMIT 100
`;
return await client.query({
query,
query_params: { sessionId }
});
}
const stmt = db.prepare('SELECT * FROM users WHERE username = ?');
const user = stmt.get(username);
XSS Prevention
import DOMPurify from 'dompurify';
function sanitizeHtml(html: string): string {
return DOMPurify.sanitize(html, {
ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a', 'p', 'br'],
ALLOWED_ATTR: ['href', 'target']
});
}
Secret Management
Environment Variables
CLICKHOUSE_PASSWORD=$(openssl rand -base64 32)
GF_SECURITY_ADMIN_PASSWORD=$(openssl rand -base64 32)
SESSION_SECRET=$(openssl rand -base64 64)
JWT_SECRET=$(openssl rand -base64 32)
WEB_UI_ADMIN_PASSWORD=$(openssl rand -base64 24)
Secret Masking in UI
function maskSecret(value: string): string {
if (value.length <= 2) return '***';
return value[0] + '*'.repeat(value.length - 2) + value[value.length - 1];
}
Rate Limiting (v2.0.0)
Authentication Endpoints
import rateLimit from 'express-rate-limit';
const authLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 5,
message: 'Too many login attempts, please try again later',
standardHeaders: true,
legacyHeaders: false
});
app.post('/api/auth/login', authLimiter, loginHandler);
app.post('/api/auth/change-password', authLimiter, changePasswordHandler);
General API Protection
const apiLimiter = rateLimit({
windowMs: 1 * 60 * 1000,
max: 100,
message: 'Too many requests, please slow down'
});
app.use('/api/', apiLimiter);
Branch Service Proxy Protection
const branchLimiter = rateLimit({
windowMs: 60 * 1000,
max: 30
});
app.use('/api/analyze/', branchLimiter);
ReDoS Protection (v2.0.0)
Pattern Timeout Limits
const PATTERN_TIMEOUT_MS = 1000;
async function matchPattern(text, pattern) {
const timeoutPromise = new Promise((_, reject) =>
setTimeout(() => reject(new Error('Pattern timeout')), PATTERN_TIMEOUT_MS)
);
const matchPromise = new Promise(resolve =>
resolve(new RegExp(pattern).test(text))
);
return Promise.race([matchPromise, timeoutPromise]);
}
Safe Regex Patterns
const unsafe = /^(a+)+$/;
const safe = /^a+$/;
const unsafe2 = /(x+x+)+y/;
const safe2 = /x+y/;
ReDoS Testing
npm install -g redos-detector
redos-detector '^(a+)+$'
cat services/workflow/config/unified_config.json | \
jq -r '.categories[].patterns[]' | \
xargs -I {} redos-detector '{}'
CORS Configuration
Development
app.use(cors({
origin: /^http:\/\/localhost(:\d+)?$/,
credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization']
}));
Production
const allowedOrigins = process.env.ALLOWED_ORIGINS?.split(',') || [];
app.use(cors({
origin: (origin, callback) => {
if (!origin || allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error('Not allowed by CORS'));
}
},
credentials: true
}));
Audit Logging
function auditLog(action: string, username: string, details: object) {
const entry = {
timestamp: new Date().toISOString(),
action,
username,
details: JSON.stringify(details),
ip: req.ip
};
fs.appendFileSync('config/audit.log', JSON.stringify(entry) + '\n');
}
auditLog('config_update', req.user.username, {
file: 'unified_config.json',
changes: diff(oldConfig, newConfig)
});
Health Check Security (v2.0.0)
Branch Service Health Checks
app.get('/api/health/branches',
authMiddleware,
async (req, res) => {
try {
const healthChecks = await Promise.allSettled([
fetch('http://heuristics-service:5005/health', { signal: AbortSignal.timeout(2000) }),
fetch('http://semantic-service:5006/health', { signal: AbortSignal.timeout(2000) }),
fetch('http://prompt-guard-api:8000/health', { signal: AbortSignal.timeout(2000) })
]);
const results = {
branch_a: {
name: 'Heuristics',
port: 5005,
healthy: healthChecks[0].status === 'fulfilled' && healthChecks[0].value.ok
},
branch_b: {
name: 'Semantic',
port: 5006,
healthy: healthChecks[1].status === 'fulfilled' && healthChecks[]..
},
: {
: ,
: ,
: healthChecks[]. === && healthChecks[]..
}
};
allHealthy = .(results).( b.);
res.(allHealthy ? : ).(results);
} (error) {
res.().({ : });
}
}
);
Docker Health Checks
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:8787/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s
Security Testing
OWASP Top 10 Coverage
Coverage (v2.0.0):
- ✅ Broken Access Control (RBAC, last admin protection)
- ✅ Cryptographic Failures (bcrypt, JWT, auto-generated secrets)
- ✅ Injection Attacks (parameterized queries, input validation)
- ✅ Insecure Design (defense in depth, fail-secure)
- ✅ Security Misconfiguration (defaults secure, audit logging)
- ✅ Vulnerable Components (pinned versions, SHA digests)
- ✅ Identification & Authentication (JWT, session management)
Security Tools
trufflehog filesystem --directory . --only-verified
cd services/web-ui/backend && npm audit
cd services/workflow && npm test -- security
Code Review Checklist (v2.0.0)
## Security Review
- [ ] No hardcoded secrets
- [ ] Input validation present
- [ ] SQL queries parameterized
- [ ] Permissions checked server-side
- [ ] Passwords hashed with bcrypt (12 rounds)
- [ ] CORS configured properly
- [ ] Audit logging implemented
- [ ] ETag used for concurrent edits
## 3-Branch Security (v2.0.0)
- [ ] Branch timeouts configured (A:1000ms, B:2000ms, C:3000ms)
- [ ] Degradation handled (fail-safe to BLOCK)
- [ ] Arbiter thresholds not exposed to input
- [ ] Branch services isolated (no external network)
- [ ] unified_config.json validated before loading
Related Skills
react-tailwind-vigil-ui - Frontend security patterns
n8n-vigil-workflow - 3-branch workflow security
docker-vigil-orchestration - 11 service security
express-api-developer - API security patterns
References
- OWASP Top 10: https://owasp.org/www-project-top-ten/
- Security docs:
docs/SECURITY.md
- Auth docs:
docs/AUTHENTICATION.md
- unified_config.json:
services/workflow/config/unified_config.json (303 lines, v5.0.0)
Last Updated: 2025-12-09
Version: v2.0.0
Architecture: 3-Branch Parallel Detection
Services: 11 Docker containers