@patricio0312rev/skillset 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -0
- package/LICENSE +21 -0
- package/README.md +176 -0
- package/bin/cli.js +37 -0
- package/package.json +55 -0
- package/src/commands/init.js +301 -0
- package/src/index.js +168 -0
- package/src/lib/config.js +200 -0
- package/src/lib/generator.js +166 -0
- package/src/utils/display.js +95 -0
- package/src/utils/readme.js +196 -0
- package/src/utils/tool-specific.js +233 -0
- package/templates/ai-engineering/agent-orchestration-planner/ SKILL.md +266 -0
- package/templates/ai-engineering/cost-latency-optimizer/ SKILL.md +270 -0
- package/templates/ai-engineering/doc-to-vector-dataset-generator/ SKILL.md +239 -0
- package/templates/ai-engineering/evaluation-harness/ SKILL.md +219 -0
- package/templates/ai-engineering/guardrails-safety-filter-builder/ SKILL.md +226 -0
- package/templates/ai-engineering/llm-debugger/ SKILL.md +283 -0
- package/templates/ai-engineering/prompt-regression-tester/ SKILL.md +216 -0
- package/templates/ai-engineering/prompt-template-builder/ SKILL.md +393 -0
- package/templates/ai-engineering/rag-pipeline-builder/ SKILL.md +244 -0
- package/templates/ai-engineering/tool-function-schema-designer/ SKILL.md +219 -0
- package/templates/architecture/adr-writer/ SKILL.md +250 -0
- package/templates/architecture/api-versioning-deprecation-planner/ SKILL.md +331 -0
- package/templates/architecture/domain-model-boundaries-mapper/ SKILL.md +300 -0
- package/templates/architecture/migration-planner/ SKILL.md +376 -0
- package/templates/architecture/performance-budget-setter/ SKILL.md +318 -0
- package/templates/architecture/reliability-strategy-builder/ SKILL.md +286 -0
- package/templates/architecture/rfc-generator/ SKILL.md +362 -0
- package/templates/architecture/scalability-playbook/ SKILL.md +279 -0
- package/templates/architecture/system-design-generator/ SKILL.md +339 -0
- package/templates/architecture/tech-debt-prioritizer/ SKILL.md +329 -0
- package/templates/backend/api-contract-normalizer/ SKILL.md +487 -0
- package/templates/backend/api-endpoint-generator/ SKILL.md +415 -0
- package/templates/backend/auth-module-builder/ SKILL.md +99 -0
- package/templates/backend/background-jobs-designer/ SKILL.md +166 -0
- package/templates/backend/caching-strategist/ SKILL.md +190 -0
- package/templates/backend/error-handling-standardizer/ SKILL.md +174 -0
- package/templates/backend/rate-limiting-abuse-protection/ SKILL.md +147 -0
- package/templates/backend/rbac-permissions-builder/ SKILL.md +158 -0
- package/templates/backend/service-layer-extractor/ SKILL.md +269 -0
- package/templates/backend/webhook-receiver-hardener/ SKILL.md +211 -0
- package/templates/ci-cd/artifact-sbom-publisher/ SKILL.md +236 -0
- package/templates/ci-cd/caching-strategy-optimizer/ SKILL.md +195 -0
- package/templates/ci-cd/deployment-checklist-generator/ SKILL.md +381 -0
- package/templates/ci-cd/github-actions-pipeline-creator/ SKILL.md +348 -0
- package/templates/ci-cd/monorepo-ci-optimizer/ SKILL.md +298 -0
- package/templates/ci-cd/preview-environments-builder/ SKILL.md +187 -0
- package/templates/ci-cd/quality-gates-enforcer/ SKILL.md +342 -0
- package/templates/ci-cd/release-automation-builder/ SKILL.md +281 -0
- package/templates/ci-cd/rollback-workflow-builder/ SKILL.md +372 -0
- package/templates/ci-cd/secrets-env-manager/ SKILL.md +242 -0
- package/templates/db-management/backup-restore-runbook-generator/ SKILL.md +505 -0
- package/templates/db-management/data-integrity-auditor/ SKILL.md +505 -0
- package/templates/db-management/data-retention-archiving-planner/ SKILL.md +430 -0
- package/templates/db-management/data-seeding-fixtures-builder/ SKILL.md +375 -0
- package/templates/db-management/db-performance-watchlist/ SKILL.md +425 -0
- package/templates/db-management/etl-sync-job-builder/ SKILL.md +457 -0
- package/templates/db-management/multi-tenant-safety-checker/ SKILL.md +398 -0
- package/templates/db-management/prisma-migration-assistant/ SKILL.md +379 -0
- package/templates/db-management/schema-consistency-checker/ SKILL.md +440 -0
- package/templates/db-management/sql-query-optimizer/ SKILL.md +324 -0
- package/templates/foundation/changelog-writer/ SKILL.md +431 -0
- package/templates/foundation/code-formatter-installer/ SKILL.md +320 -0
- package/templates/foundation/codebase-summarizer/ SKILL.md +360 -0
- package/templates/foundation/dependency-doctor/ SKILL.md +163 -0
- package/templates/foundation/dev-environment-bootstrapper/ SKILL.md +259 -0
- package/templates/foundation/dev-onboarding-builder/ SKILL.md +556 -0
- package/templates/foundation/docs-starter-kit/ SKILL.md +574 -0
- package/templates/foundation/explaining-code/SKILL.md +13 -0
- package/templates/foundation/git-hygiene-enforcer/ SKILL.md +455 -0
- package/templates/foundation/project-scaffolder/ SKILL.md +65 -0
- package/templates/foundation/project-scaffolder/references/templates.md +126 -0
- package/templates/foundation/repo-structure-linter/ SKILL.md +0 -0
- package/templates/foundation/repo-structure-linter/references/conventions.md +98 -0
- package/templates/frontend/animation-micro-interaction-pack/ SKILL.md +41 -0
- package/templates/frontend/component-scaffold-generator/ SKILL.md +562 -0
- package/templates/frontend/design-to-component-translator/ SKILL.md +547 -0
- package/templates/frontend/form-wizard-builder/ SKILL.md +553 -0
- package/templates/frontend/frontend-refactor-planner/ SKILL.md +37 -0
- package/templates/frontend/i18n-frontend-implementer/ SKILL.md +44 -0
- package/templates/frontend/modal-drawer-system/ SKILL.md +377 -0
- package/templates/frontend/page-layout-builder/ SKILL.md +630 -0
- package/templates/frontend/state-ux-flow-builder/ SKILL.md +23 -0
- package/templates/frontend/table-builder/ SKILL.md +350 -0
- package/templates/performance/alerting-dashboard-builder/ SKILL.md +162 -0
- package/templates/performance/backend-latency-profiler-helper/ SKILL.md +108 -0
- package/templates/performance/caching-cdn-strategy-planner/ SKILL.md +150 -0
- package/templates/performance/capacity-planning-helper/ SKILL.md +242 -0
- package/templates/performance/core-web-vitals-tuner/ SKILL.md +126 -0
- package/templates/performance/incident-runbook-generator/ SKILL.md +162 -0
- package/templates/performance/load-test-scenario-builder/ SKILL.md +256 -0
- package/templates/performance/observability-setup/ SKILL.md +232 -0
- package/templates/performance/postmortem-writer/ SKILL.md +203 -0
- package/templates/performance/structured-logging-standardizer/ SKILL.md +122 -0
- package/templates/security/auth-security-reviewer/ SKILL.md +428 -0
- package/templates/security/dependency-vulnerability-triage/ SKILL.md +495 -0
- package/templates/security/input-validation-sanitization-auditor/ SKILL.md +76 -0
- package/templates/security/pii-redaction-logging-policy-builder/ SKILL.md +65 -0
- package/templates/security/rbac-policy-tester/ SKILL.md +80 -0
- package/templates/security/secrets-scanner/ SKILL.md +462 -0
- package/templates/security/secure-headers-csp-builder/ SKILL.md +404 -0
- package/templates/security/security-incident-playbook-generator/ SKILL.md +76 -0
- package/templates/security/security-pr-checklist-skill/ SKILL.md +62 -0
- package/templates/security/threat-model-generator/ SKILL.md +394 -0
- package/templates/testing/contract-testing-builder/ SKILL.md +492 -0
- package/templates/testing/coverage-strategist/ SKILL.md +436 -0
- package/templates/testing/e2e-test-builder/ SKILL.md +382 -0
- package/templates/testing/flaky-test-detective/ SKILL.md +416 -0
- package/templates/testing/integration-test-builder/ SKILL.md +525 -0
- package/templates/testing/mocking-assistant/ SKILL.md +383 -0
- package/templates/testing/snapshot-test-refactorer/ SKILL.md +375 -0
- package/templates/testing/test-data-factory-builder/ SKILL.md +449 -0
- package/templates/testing/test-reporting-triage-skill/ SKILL.md +469 -0
- package/templates/testing/unit-test-generator/ SKILL.md +548 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: structured-logging-standardizer
|
|
3
|
+
description: Enforces consistent structured logging with request correlation IDs, standardized log schema, middleware integration, and best practices. Use for "structured logging", "log standardization", "request tracing", or "log correlation".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Structured Logging Standardizer
|
|
7
|
+
|
|
8
|
+
Implement consistent, queryable, correlated logs.
|
|
9
|
+
|
|
10
|
+
## Log Schema
|
|
11
|
+
|
|
12
|
+
```typescript
|
|
13
|
+
interface LogEntry {
|
|
14
|
+
timestamp: string; // ISO 8601
|
|
15
|
+
level: "debug" | "info" | "warn" | "error" | "fatal";
|
|
16
|
+
message: string;
|
|
17
|
+
service: string;
|
|
18
|
+
environment: string;
|
|
19
|
+
|
|
20
|
+
// Request context
|
|
21
|
+
requestId?: string;
|
|
22
|
+
traceId?: string;
|
|
23
|
+
userId?: string;
|
|
24
|
+
|
|
25
|
+
// Additional context
|
|
26
|
+
[key: string]: any;
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Request ID Middleware
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import { v4 as uuidv4 } from "uuid";
|
|
34
|
+
|
|
35
|
+
app.use((req, res, next) => {
|
|
36
|
+
// Generate or use existing request ID
|
|
37
|
+
req.id = req.headers["x-request-id"] || uuidv4();
|
|
38
|
+
|
|
39
|
+
// Add to response headers
|
|
40
|
+
res.setHeader("x-request-id", req.id);
|
|
41
|
+
|
|
42
|
+
// Store in async local storage
|
|
43
|
+
asyncLocalStorage.run(new Map(), () => {
|
|
44
|
+
asyncLocalStorage.getStore()?.set("requestId", req.id);
|
|
45
|
+
next();
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// Logger with request context
|
|
50
|
+
const logger = pino({
|
|
51
|
+
mixin() {
|
|
52
|
+
return {
|
|
53
|
+
requestId: asyncLocalStorage.getStore()?.get("requestId"),
|
|
54
|
+
};
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Standardized Logger
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
class StandardLogger {
|
|
63
|
+
private logger = pino();
|
|
64
|
+
|
|
65
|
+
info(message: string, context?: Record<string, any>) {
|
|
66
|
+
this.logger.info(
|
|
67
|
+
{
|
|
68
|
+
...this.getContext(),
|
|
69
|
+
...context,
|
|
70
|
+
},
|
|
71
|
+
message
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
error(message: string, error?: Error, context?: Record<string, any>) {
|
|
76
|
+
this.logger.error(
|
|
77
|
+
{
|
|
78
|
+
...this.getContext(),
|
|
79
|
+
...context,
|
|
80
|
+
error: {
|
|
81
|
+
message: error?.message,
|
|
82
|
+
stack: error?.stack,
|
|
83
|
+
name: error?.name,
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
message
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
private getContext() {
|
|
91
|
+
return {
|
|
92
|
+
requestId: asyncLocalStorage.getStore()?.get("requestId"),
|
|
93
|
+
userId: asyncLocalStorage.getStore()?.get("userId"),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Best Practices
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
// ✅ DO: Structured fields
|
|
103
|
+
logger.info({ userId: '123', action: 'purchase', amount: 99.99 }, 'Purchase completed');
|
|
104
|
+
|
|
105
|
+
// ❌ DON'T: String interpolation
|
|
106
|
+
logger.info(\`User 123 purchased for $99.99\`);
|
|
107
|
+
|
|
108
|
+
// ✅ DO: Consistent field names
|
|
109
|
+
logger.info({ duration_ms: 150 }, 'Request completed');
|
|
110
|
+
|
|
111
|
+
// ❌ DON'T: Inconsistent naming
|
|
112
|
+
logger.info({ durationMs: 150 }, 'Request done');
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Output Checklist
|
|
116
|
+
|
|
117
|
+
- [ ] Request ID middleware
|
|
118
|
+
- [ ] Structured log schema
|
|
119
|
+
- [ ] Correlation IDs
|
|
120
|
+
- [ ] Standardized logger
|
|
121
|
+
- [ ] Best practices documented
|
|
122
|
+
ENDFILE
|
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: auth-security-reviewer
|
|
3
|
+
description: Reviews authentication and authorization implementation for session management, CSRF, cookie security, and auth flow vulnerabilities with findings, severity assessment, and fix recommendations. Use for "auth review", "session security", "CSRF protection", or "authentication audit".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Auth Security Reviewer
|
|
7
|
+
|
|
8
|
+
Comprehensive security review of authentication systems.
|
|
9
|
+
|
|
10
|
+
## Session Security Checklist
|
|
11
|
+
|
|
12
|
+
```typescript
|
|
13
|
+
// ❌ INSECURE Session Configuration
|
|
14
|
+
app.use(
|
|
15
|
+
session({
|
|
16
|
+
secret: "weak-secret", // Too simple
|
|
17
|
+
resave: true, // Unnecessary
|
|
18
|
+
saveUninitialized: true, // Creates unnecessary sessions
|
|
19
|
+
cookie: {
|
|
20
|
+
secure: false, // Not HTTPS-only
|
|
21
|
+
httpOnly: false, // Accessible via JavaScript
|
|
22
|
+
sameSite: false, // CSRF vulnerable
|
|
23
|
+
maxAge: 365 * 24 * 60 * 60 * 1000, // 1 year - too long
|
|
24
|
+
},
|
|
25
|
+
})
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
// ✅ SECURE Session Configuration
|
|
29
|
+
app.use(
|
|
30
|
+
session({
|
|
31
|
+
secret: process.env.SESSION_SECRET, // From environment
|
|
32
|
+
resave: false,
|
|
33
|
+
saveUninitialized: false,
|
|
34
|
+
name: "sessionId", // Don't use default 'connect.sid'
|
|
35
|
+
cookie: {
|
|
36
|
+
secure: true, // HTTPS only
|
|
37
|
+
httpOnly: true, // No JavaScript access
|
|
38
|
+
sameSite: "strict", // CSRF protection
|
|
39
|
+
maxAge: 24 * 60 * 60 * 1000, // 24 hours
|
|
40
|
+
domain: process.env.COOKIE_DOMAIN,
|
|
41
|
+
},
|
|
42
|
+
store: new RedisStore({
|
|
43
|
+
client: redisClient,
|
|
44
|
+
ttl: 86400,
|
|
45
|
+
}),
|
|
46
|
+
})
|
|
47
|
+
);
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## JWT Security Review
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
// ❌ INSECURE JWT Implementation
|
|
54
|
+
const token = jwt.sign(
|
|
55
|
+
{ userId: user.id },
|
|
56
|
+
"weak-secret", // Hardcoded secret
|
|
57
|
+
{ algorithm: "HS256" } // No expiration
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
// Store in localStorage
|
|
61
|
+
localStorage.setItem("token", token); // XSS vulnerable
|
|
62
|
+
|
|
63
|
+
// ✅ SECURE JWT Implementation
|
|
64
|
+
const token = jwt.sign(
|
|
65
|
+
{
|
|
66
|
+
userId: user.id,
|
|
67
|
+
role: user.role,
|
|
68
|
+
iat: Math.floor(Date.now() / 1000),
|
|
69
|
+
},
|
|
70
|
+
process.env.JWT_SECRET, // Strong secret from env
|
|
71
|
+
{
|
|
72
|
+
algorithm: "HS256",
|
|
73
|
+
expiresIn: "15m", // Short-lived
|
|
74
|
+
issuer: "myapp.com",
|
|
75
|
+
audience: "myapp.com",
|
|
76
|
+
}
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
// Store in httpOnly cookie
|
|
80
|
+
res.cookie("accessToken", token, {
|
|
81
|
+
httpOnly: true,
|
|
82
|
+
secure: true,
|
|
83
|
+
sameSite: "strict",
|
|
84
|
+
maxAge: 15 * 60 * 1000,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Refresh token with longer expiry
|
|
88
|
+
const refreshToken = jwt.sign(
|
|
89
|
+
{ userId: user.id, type: "refresh" },
|
|
90
|
+
process.env.REFRESH_TOKEN_SECRET,
|
|
91
|
+
{ expiresIn: "7d" }
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
// Store refresh token in database
|
|
95
|
+
await storeRefreshToken(user.id, refreshToken);
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## CSRF Protection
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
// Using csurf middleware
|
|
102
|
+
import csrf from "csurf";
|
|
103
|
+
|
|
104
|
+
const csrfProtection = csrf({ cookie: true });
|
|
105
|
+
|
|
106
|
+
// Apply to state-changing routes
|
|
107
|
+
app.post("/api/transfer", csrfProtection, async (req, res) => {
|
|
108
|
+
// Protected from CSRF
|
|
109
|
+
await processTransfer(req.body);
|
|
110
|
+
res.json({ success: true });
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// Provide CSRF token to frontend
|
|
114
|
+
app.get("/api/csrf-token", csrfProtection, (req, res) => {
|
|
115
|
+
res.json({ csrfToken: req.csrfToken() });
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// Frontend usage
|
|
119
|
+
const csrfToken = await fetch("/api/csrf-token").then((r) => r.json());
|
|
120
|
+
|
|
121
|
+
await fetch("/api/transfer", {
|
|
122
|
+
method: "POST",
|
|
123
|
+
headers: {
|
|
124
|
+
"Content-Type": "application/json",
|
|
125
|
+
"X-CSRF-Token": csrfToken.csrfToken,
|
|
126
|
+
},
|
|
127
|
+
body: JSON.stringify({ amount: 100 }),
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Password Security
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
// ❌ INSECURE Password Handling
|
|
135
|
+
const password = req.body.password;
|
|
136
|
+
const hash = crypto.createHash("md5").update(password).digest("hex"); // MD5 is broken
|
|
137
|
+
await db.user.create({ password: hash });
|
|
138
|
+
|
|
139
|
+
// ✅ SECURE Password Handling
|
|
140
|
+
import bcrypt from "bcrypt";
|
|
141
|
+
|
|
142
|
+
// Hashing
|
|
143
|
+
const saltRounds = 12; // Adjust based on security requirements
|
|
144
|
+
const hash = await bcrypt.hash(password, saltRounds);
|
|
145
|
+
await db.user.create({ passwordHash: hash });
|
|
146
|
+
|
|
147
|
+
// Verification
|
|
148
|
+
const isValid = await bcrypt.compare(password, user.passwordHash);
|
|
149
|
+
|
|
150
|
+
// Password requirements
|
|
151
|
+
function validatePassword(password: string): boolean {
|
|
152
|
+
return (
|
|
153
|
+
password.length >= 12 &&
|
|
154
|
+
/[A-Z]/.test(password) && // Uppercase
|
|
155
|
+
/[a-z]/.test(password) && // Lowercase
|
|
156
|
+
/[0-9]/.test(password) && // Number
|
|
157
|
+
/[^A-Za-z0-9]/.test(password) // Special char
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Check against breached passwords
|
|
162
|
+
import { pwnedPassword } from "hibp";
|
|
163
|
+
|
|
164
|
+
const breachCount = await pwnedPassword(password);
|
|
165
|
+
if (breachCount > 0) {
|
|
166
|
+
throw new Error("This password has been found in data breaches");
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Multi-Factor Authentication
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
// TOTP-based MFA
|
|
174
|
+
import speakeasy from "speakeasy";
|
|
175
|
+
import qrcode from "qrcode";
|
|
176
|
+
|
|
177
|
+
// Generate secret
|
|
178
|
+
const secret = speakeasy.generateSecret({
|
|
179
|
+
name: `MyApp (${user.email})`,
|
|
180
|
+
issuer: "MyApp",
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
// Store secret
|
|
184
|
+
await db.user.update({
|
|
185
|
+
where: { id: user.id },
|
|
186
|
+
data: {
|
|
187
|
+
mfaSecret: secret.base32,
|
|
188
|
+
mfaEnabled: false, // Not enabled until verified
|
|
189
|
+
},
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// Generate QR code
|
|
193
|
+
const qrCodeUrl = await qrcode.toDataURL(secret.otpauth_url);
|
|
194
|
+
|
|
195
|
+
// Verify TOTP token
|
|
196
|
+
function verifyMFA(token: string, secret: string): boolean {
|
|
197
|
+
return speakeasy.totp.verify({
|
|
198
|
+
secret,
|
|
199
|
+
encoding: "base32",
|
|
200
|
+
token,
|
|
201
|
+
window: 2, // Allow 2 time steps before/after
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Backup codes
|
|
206
|
+
function generateBackupCodes(): string[] {
|
|
207
|
+
return Array.from({ length: 10 }, () =>
|
|
208
|
+
crypto.randomBytes(4).toString("hex").toUpperCase()
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## Authorization Vulnerabilities
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
// ❌ INSECURE: Missing authorization check
|
|
217
|
+
app.get("/api/users/:id/profile", async (req, res) => {
|
|
218
|
+
const profile = await db.user.findUnique({
|
|
219
|
+
where: { id: req.params.id },
|
|
220
|
+
});
|
|
221
|
+
res.json(profile); // Anyone can access any profile!
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
// ✅ SECURE: Proper authorization
|
|
225
|
+
app.get("/api/users/:id/profile", authenticate, async (req, res) => {
|
|
226
|
+
// Check if user can access this profile
|
|
227
|
+
if (req.user.id !== req.params.id && req.user.role !== "ADMIN") {
|
|
228
|
+
return res.status(403).json({ error: "Forbidden" });
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const profile = await db.user.findUnique({
|
|
232
|
+
where: { id: req.params.id },
|
|
233
|
+
});
|
|
234
|
+
res.json(profile);
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
// ❌ INSECURE: IDOR vulnerability
|
|
238
|
+
app.delete("/api/orders/:id", async (req, res) => {
|
|
239
|
+
await db.order.delete({ where: { id: req.params.id } });
|
|
240
|
+
res.json({ success: true });
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
// ✅ SECURE: Verify ownership
|
|
244
|
+
app.delete("/api/orders/:id", authenticate, async (req, res) => {
|
|
245
|
+
const order = await db.order.findUnique({
|
|
246
|
+
where: { id: req.params.id },
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
if (!order) {
|
|
250
|
+
return res.status(404).json({ error: "Not found" });
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (order.userId !== req.user.id) {
|
|
254
|
+
return res.status(403).json({ error: "Forbidden" });
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
await db.order.delete({ where: { id: req.params.id } });
|
|
258
|
+
res.json({ success: true });
|
|
259
|
+
});
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
## Session Fixation Prevention
|
|
263
|
+
|
|
264
|
+
```typescript
|
|
265
|
+
// ❌ INSECURE: Session not regenerated on login
|
|
266
|
+
app.post("/login", async (req, res) => {
|
|
267
|
+
const user = await authenticate(req.body);
|
|
268
|
+
req.session.userId = user.id;
|
|
269
|
+
res.json({ success: true });
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
// ✅ SECURE: Regenerate session on login
|
|
273
|
+
app.post("/login", async (req, res) => {
|
|
274
|
+
const user = await authenticate(req.body);
|
|
275
|
+
|
|
276
|
+
// Regenerate session to prevent fixation
|
|
277
|
+
req.session.regenerate((err) => {
|
|
278
|
+
if (err) return res.status(500).json({ error: "Server error" });
|
|
279
|
+
|
|
280
|
+
req.session.userId = user.id;
|
|
281
|
+
res.json({ success: true });
|
|
282
|
+
});
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
// Also regenerate on privilege escalation
|
|
286
|
+
app.post("/admin/elevate", async (req, res) => {
|
|
287
|
+
// Verify admin credentials
|
|
288
|
+
await verifyAdminPassword(req.body.password);
|
|
289
|
+
|
|
290
|
+
// Regenerate session
|
|
291
|
+
req.session.regenerate((err) => {
|
|
292
|
+
if (err) return res.status(500).json({ error: "Server error" });
|
|
293
|
+
|
|
294
|
+
req.session.isAdmin = true;
|
|
295
|
+
res.json({ success: true });
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
## Rate Limiting on Auth Endpoints
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
import rateLimit from "express-rate-limit";
|
|
304
|
+
|
|
305
|
+
// Strict rate limit for login
|
|
306
|
+
const loginLimiter = rateLimit({
|
|
307
|
+
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
308
|
+
max: 5, // 5 attempts
|
|
309
|
+
message: "Too many login attempts, please try again later",
|
|
310
|
+
standardHeaders: true,
|
|
311
|
+
legacyHeaders: false,
|
|
312
|
+
// Use IP + username for more granular limiting
|
|
313
|
+
keyGenerator: (req) => `${req.ip}-${req.body.email}`,
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
app.post("/api/login", loginLimiter, async (req, res) => {
|
|
317
|
+
// Login logic
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
// Even stricter for password reset
|
|
321
|
+
const resetLimiter = rateLimit({
|
|
322
|
+
windowMs: 60 * 60 * 1000, // 1 hour
|
|
323
|
+
max: 3,
|
|
324
|
+
message: "Too many password reset attempts",
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
app.post("/api/password-reset", resetLimiter, async (req, res) => {
|
|
328
|
+
// Password reset logic
|
|
329
|
+
});
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
## Security Testing
|
|
333
|
+
|
|
334
|
+
```typescript
|
|
335
|
+
// tests/auth-security.test.ts
|
|
336
|
+
describe("Auth Security", () => {
|
|
337
|
+
describe("Session Security", () => {
|
|
338
|
+
it("should set httpOnly cookie", async () => {
|
|
339
|
+
const response = await request(app)
|
|
340
|
+
.post("/api/login")
|
|
341
|
+
.send({ email: "test@example.com", password: "password123" });
|
|
342
|
+
|
|
343
|
+
const cookie = response.headers["set-cookie"][0];
|
|
344
|
+
expect(cookie).toContain("HttpOnly");
|
|
345
|
+
expect(cookie).toContain("Secure");
|
|
346
|
+
expect(cookie).toContain("SameSite=Strict");
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
it("should regenerate session on login", async () => {
|
|
350
|
+
const agent = request.agent(app);
|
|
351
|
+
|
|
352
|
+
// Get initial session
|
|
353
|
+
await agent.get("/");
|
|
354
|
+
const initialCookie = agent.jar.getCookie("sessionId");
|
|
355
|
+
|
|
356
|
+
// Login
|
|
357
|
+
await agent.post("/api/login").send({
|
|
358
|
+
email: "test@example.com",
|
|
359
|
+
password: "password123",
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
const loginCookie = agent.jar.getCookie("sessionId");
|
|
363
|
+
|
|
364
|
+
// Session ID should change
|
|
365
|
+
expect(loginCookie.value).not.toBe(initialCookie.value);
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
describe("CSRF Protection", () => {
|
|
370
|
+
it("should reject requests without CSRF token", async () => {
|
|
371
|
+
await request(app)
|
|
372
|
+
.post("/api/transfer")
|
|
373
|
+
.send({ amount: 100 })
|
|
374
|
+
.expect(403);
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
it("should accept requests with valid CSRF token", async () => {
|
|
378
|
+
const { csrfToken } = await request(app)
|
|
379
|
+
.get("/api/csrf-token")
|
|
380
|
+
.then((r) => r.body);
|
|
381
|
+
|
|
382
|
+
await request(app)
|
|
383
|
+
.post("/api/transfer")
|
|
384
|
+
.set("X-CSRF-Token", csrfToken)
|
|
385
|
+
.send({ amount: 100 })
|
|
386
|
+
.expect(200);
|
|
387
|
+
});
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
describe("Authorization", () => {
|
|
391
|
+
it("should prevent IDOR attacks", async () => {
|
|
392
|
+
const user1 = await createUser();
|
|
393
|
+
const user2 = await createUser();
|
|
394
|
+
|
|
395
|
+
const token1 = generateToken(user1);
|
|
396
|
+
|
|
397
|
+
// Try to access user2's profile with user1's token
|
|
398
|
+
await request(app)
|
|
399
|
+
.get(`/api/users/${user2.id}/profile`)
|
|
400
|
+
.set("Authorization", `Bearer ${token1}`)
|
|
401
|
+
.expect(403);
|
|
402
|
+
});
|
|
403
|
+
});
|
|
404
|
+
});
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
## Best Practices
|
|
408
|
+
|
|
409
|
+
1. **Regenerate sessions**: On login and privilege changes
|
|
410
|
+
2. **Short-lived tokens**: 15min access, 7-day refresh
|
|
411
|
+
3. **CSRF protection**: All state-changing operations
|
|
412
|
+
4. **Rate limiting**: Prevent brute force
|
|
413
|
+
5. **Secure cookies**: HttpOnly, Secure, SameSite
|
|
414
|
+
6. **MFA**: For sensitive operations
|
|
415
|
+
7. **Audit logs**: Track authentication events
|
|
416
|
+
|
|
417
|
+
## Output Checklist
|
|
418
|
+
|
|
419
|
+
- [ ] Session configuration reviewed
|
|
420
|
+
- [ ] JWT implementation secured
|
|
421
|
+
- [ ] CSRF protection enabled
|
|
422
|
+
- [ ] Password hashing with bcrypt
|
|
423
|
+
- [ ] MFA implementation (if required)
|
|
424
|
+
- [ ] Authorization checks on all endpoints
|
|
425
|
+
- [ ] Session fixation prevention
|
|
426
|
+
- [ ] Rate limiting on auth endpoints
|
|
427
|
+
- [ ] Security tests written
|
|
428
|
+
- [ ] Audit logging configured
|