Security PatternsSAFE
Universal Claude Code workflow plugin with agents, skills, hooks, and commands
Overview
Universal Claude Code workflow plugin with agents, skills, hooks, and commands
e93daf1e69daOBSERVED · 2026-10-08What it tells the agent
The instruction file, verbatim from the audited commit — this is the text the model reads, and the surface the audit's instruction layer examines. Quoted here so you can judge it without cloning anything.
---
name: security-patterns
description: Implements authentication, authorization, encryption, secrets management, and security hardening patterns. Use when designing auth flows, managing secrets, configuring CORS, implementing rate limiting, or when asked about JWT, OAuth, password hashing, API keys, RBAC, or security best practices.
---
# Security Patterns
### When to Load
- **Trigger**: Auth flows, encryption, secrets management, CORS configuration, input validation, rate limiting
- **Skip**: No security surface involved in the current task
## Security Implementation Workflow
Copy this checklist and track progress:
```
Security Implementation Progress:
- [ ] Step 1: Choose authentication strategy
- [ ] Step 2: Implement authorization model
- [ ] Step 3: Set up password hashing
- [ ] Step 4: Configure secrets management
- [ ] Step 5: Enable encryption (transit + rest)
- [ ] Step 6: Configure CORS
- [ ] Step 7: Add rate limiting
- [ ] Step 8: Validate against anti-patterns checklist
```
## Authentication Patterns
### JWT (JSON Web Tokens)
```typescript
import jwt from "jsonwebtoken";
function generateTokens(user: User) {
const accessToken = jwt.sign(
{ sub: user.id, role: user.role },
process.env.JWT_SECRET!,
{ expiresIn: "15m", algorithm: "HS256" },
);
const refreshToken = jwt.sign(
{ sub: user.id, tokenVersion: user.tokenVersion },
process.env.JWT_REFRESH_SECRET!,
{ expiresIn: "7d" },
);
return { accessToken, refreshToken };
}
// WRONG: localStorage (XSS vulnerable) | CORRECT: httpOnly cookie for refresh, memory for access
res.cookie("refreshToken", refreshToken, {
httpOnly: true,
secure: true,
sameSite: "strict",
maxAge: 7 * 24 * 60 * 60 * 1000,
path: "/api/auth/refresh",
});
```
### JWT Verification Middleware
```typescript
function authenticate(req: Request, res: Response, next: NextFunction) {
const header = req.headers.authorization;
if (!header?.startsWith("Bearer ")) {
return res.status(401).json({ error: "Missing token" });
}
try {
const token = header.slice(7);
const payload = jwt.verify(token, process.env.JWT_SECRET!, {
algorithms: ["HS256"], // pin: never let the token choose its algorithm
}) as JwtPayload;
req.user = { id: payload.sub, role: payload.role };
next();
} catch (err) {
if (err instanceof jwt.TokenExpiredError) {
return res.status(401).json({ error: "Token expired" });
}
return res.status(401).json({ error: "Invalid token" });
}
}
```
### Session-Based Auth
```typescript
import session from "express-session";
import { RedisStore } from "connect-redis";
app.use(
session({
store: new RedisStore({ client: redisClient }),
secret: process.env.SESSION_SECRET!,
resave: false,
saveUninitialized: false,
cookie: {
httpOnly: true,
secure: process.env.NODE_ENV === "production",
sameSite: "strict",
maxAge: 24 * 60 * 60 * 1000, // 24 hours
},
}),
);
```
### OAuth 2.0 / OIDC Flow Summary
```
Authorization Code Flow with PKCE (all clients):
1. Redirect to provider: /authorize?response_type=code&client_id=...&redirect_uri=...&scope=openid email
&state=RANDOM&nonce=RANDOM&code_challenge=...&code_challenge_method=S256
2. User authenticates, provider redirects back with ?code=AUTHORIZATION_CODE&state=... (reject if state differs)
3. Backend exchanges code for tokens (POST /token with code_verifier, plus client_secret for confidential clients)
4. Backend validates the id_token (signature, iss, aud, exp, nonce), then creates session/JWT
Public clients (SPAs, mobile): same flow without client_secret
NEVER use Implicit Flow (deprecated, tokens exposed in URL)
```
### API Key Authentication
```typescript
async function authenticateApiKey(
req: Request,
res: Response,
next: NextFunction,
) {
const apiKey = req.headers["x-api-key"] as string;
if (!apiKey) return res.status(401).json({ error: "API key required" });
// WRONG: Direct comparison (timing attack) | CORRECT: Hash-based lookup
const hashedKey = crypto.createHash("sha256").update(apiKey).digest("hex");
const keyRecord = await db.apiKey.findUnique({ where: { hash: hashedKey } });
if (!keyRecord || keyRecord.revokedAt)
return res.status(401).json({ error: "Invalid API key" });
req.apiClient = { id: keyRecord.clientId, scopes: keyRecord.scopes };
next();
}
```
## Authorization Models
### RBAC (Role-Based Access Control)
```typescript
const PERMISSIONS = {
admin: [
"users:read",
"users:write",
"users:delete",
"posts:read",
"posts:write",
"posts:delete",
],
editor: ["posts:read", "posts:write", "posts:delete", "users:read"],
viewer: ["posts:read", "users:read"],
} as const;
type Role = keyof typeof PERMISSIONS;
function authorize(...requiredPermissions: string[]) {
return (req: Request, res: Response, next: NextFunction) => {
const userPermissions = PERMISSIONS[req.user.role as Role] || [];
const hasPermission = requiredPermissions.every((p) =>
(userPermissions as readonly string[]).includes(p),
);
if (!hasPermission)
return res.status(403).json({ error: "Insufficient permissions" });
next();
};
}
// Usage: app.delete("/api/users/:id", authenticate, authorize("users:delete"), deleteUser);
```
### Resource-Level Authorization
```typescript
// WRONG: Only checking role, not ownership -- any editor can edit ANY post
// CORRECT: Check ownership or admin role
app.put(
"/api/posts/:id",
authenticate,
authorize("posts:write"),
async (req, res) => {
const post = await db.post.findUnique({ where: { id: req.params.id } });
if (!post) return res.status(404).json({ error: "Not found" });
if (post.authorId !== req.user.id && req.user.role !== "admin") {
return res
.status(403)
.json({ error: "Not authorized to edit this post" });
}
// WRONG: data: req.body -- mass assignment lets the client overwrite authorId
const Trust audit
SAFEgrade B · trust 89/100 Nothing in the source contradicts what it says it does. Grade A is reserved for packages that have also passed the behavioural sandbox.
| Layer | What it checks | Result |
|---|---|---|
| L0 | Provenance & inventory | PASS |
| L1 | Static analysis of the code | NA |
| L2 | Instruction surface (what it tells the agent) | PASS |
| L3 | Class-specific surface | PASS |
| L4 | Behavioural (sandbox) | SKIPPED |
What the source does
- Filesystem
- none-observed
- Network
- none-observed
- Shell
- none-observed
- Dependencies
- pinned
- Secrets in source
- none-found
Findings (0)
No findings outside the package's declared scope.
Gates applied: no_behavioural_pass.
e93daf1e69dafull audit observations/trust-audit/skill/cloudai-x__security-patterns.json · Report an issue / request a re-scanAudit history
Every audit this skill has had.
| Date | Source | Verdict | Grade | Score | Change |
|---|---|---|---|---|---|
| 2026-10-08 | e93daf1e69da | SAFE | B | 89 | first audit |
Questions
What does the Security Patterns skill do?
Universal Claude Code workflow plugin with agents, skills, hooks, and commands
Is Security Patterns safe to install?
The audit found nothing in the source that contradicts what it says it does, and graded it B (89/100). Grade A is held back for packages that have also passed a sandboxed behavioural run, which is why a clean skill reads B.
What can Security Patterns access on my machine?
The audit observed no filesystem, network or shell use at all in its source.
How current is this page?
The grade is for one exact copy of the source (e93daf1e69da), read on 2026-10-08. The repository is watched, and a new audit runs when it changes — this is the first audit.