From PACT
Provides SACROSANCT security rules and patterns for PACT framework development, including credential protection, backend proxy architecture, input validation with Express.js, and vulnerability checklists.
npx claudepluginhub synaptic-labs-ai/pact-plugin --plugin PACTThis skill uses the workspace's default tool permissions.
Security guidance for PACT development phases. This skill provides essential security
Provides patterns for JWT/session/OAuth auth, RBAC authorization, encryption, secrets, CORS, rate limiting, and security checklists for web apps.
Implements security best practices across app stacks including API security, authentication/authorization, input validation, encryption, and monitoring. Covers OWASP Top 10.
Enforces OWASP security patterns, secrets management via gitignore and secure env vars with Zod/Pydantic validation, and security testing setup. Use for auth, user input, API keys, security reviews.
Share bugs, ideas, or general feedback.
Security guidance for PACT development phases. This skill provides essential security patterns and links to detailed references for comprehensive implementation.
These rules are ABSOLUTE and must NEVER be violated.
NEVER ALLOW in version control:
ONLY acceptable locations for actual credentials:
| Location | Example | Security Level |
|---|---|---|
.env files in .gitignore | API_KEY=sk-xxx | Development |
Server-side process.env | process.env.API_KEY | Runtime |
| Deployment platform secrets | Railway, Vercel, AWS | Production |
| Secrets managers | Vault, AWS Secrets Manager | Enterprise |
In Documentation - Always Use Placeholders:
# Configuration
Set your API key in `.env`:
API_KEY=your_api_key_here
WRONG: Frontend --> External API (credentials in frontend)
CORRECT: Frontend --> Backend Proxy --> External API
Architecture Requirements:
/api/resource) without credentialsVerification Checklist:
# Build the application
npm run build
# Search for exposed credentials in bundle
grep -r "sk-" dist/assets/*.js
grep -r "api_key" dist/assets/*.js
grep -r "VITE_" dist/assets/*.js
# All above should return NO results
Always validate on the server side:
// Express.js example
const { body, validationResult } = require('express-validator');
app.post('/api/user',
body('email').isEmail().normalizeEmail(),
body('name').trim().escape().isLength({ min: 1, max: 100 }),
body('age').isInt({ min: 0, max: 150 }),
(req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
// Process validated input
}
);
Prevent XSS by encoding output:
// React (automatic encoding)
return <div>{userInput}</div>; // Safe - React escapes
// Dangerous - avoid unless absolutely necessary
return <div dangerouslySetInnerHTML={{__html: userInput}} />; // UNSAFE
// Node.js HTML response
const escapeHtml = (str) => str
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
Always use parameterized queries:
// WRONG - SQL Injection vulnerable
const query = `SELECT * FROM users WHERE id = ${userId}`;
// CORRECT - Parameterized query
const query = 'SELECT * FROM users WHERE id = $1';
const result = await db.query(query, [userId]);
// ORM example (Prisma)
const user = await prisma.user.findUnique({
where: { id: userId } // Safe - Prisma handles escaping
});
Password Storage:
const bcrypt = require('bcrypt');
// Hashing password
const saltRounds = 12; // Minimum recommended
const hashedPassword = await bcrypt.hash(password, saltRounds);
// Verifying password
const isValid = await bcrypt.compare(password, hashedPassword);
Session Configuration:
app.use(session({
secret: process.env.SESSION_SECRET, // Strong, random secret
resave: false,
saveUninitialized: false,
cookie: {
secure: true, // HTTPS only
httpOnly: true, // No JavaScript access
sameSite: 'strict', // CSRF protection
maxAge: 3600000 // 1 hour
}
}));
Essential HTTP headers:
const helmet = require('helmet');
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "data:", "https:"],
connectSrc: ["'self'"],
frameSrc: ["'none'"],
objectSrc: ["'none'"]
}
},
hsts: {
maxAge: 31536000,
includeSubDomains: true
}
}));
Protect against abuse:
const rateLimit = require('express-rate-limit');
// General API rate limit
const apiLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100,
message: { error: 'Too many requests, please try again later' }
});
// Stricter limit for auth endpoints
const authLimiter = rateLimit({
windowMs: 60 * 60 * 1000, // 1 hour
max: 5,
message: { error: 'Too many login attempts' }
});
app.use('/api/', apiLimiter);
app.use('/api/auth/', authLimiter);
Before any commit or deployment, verify:
git diff --staged | grep -i "key\|secret\|password").env files listed in .gitignoreFor comprehensive security guidance, see:
OWASP Top 10 Mitigations: references/owasp-top-10.md
Authentication Patterns: references/authentication-patterns.md
Data Protection: references/data-protection.md