typescript-security
# TypeScript Security Skill
What this skill does
# TypeScript Security Skill
> **USE WHEN:** Securing TypeScript/JavaScript applications, reviewing frontend/backend code for vulnerabilities.
> **DO NOT USE FOR:** Code quality issues (use typescript-quality), general TypeScript patterns, styling.
## OWASP Top 10 for TypeScript
### A01: Broken Access Control
```typescript
// Bad: No authorization check
app.get('/api/users/:id', async (req, res) => {
const user = await User.findById(req.params.id);
res.json(user);
});
// Good: Ownership verification
app.get('/api/users/:id', authenticate, async (req, res) => {
const userId = req.params.id;
if (req.user.id !== userId && !req.user.roles.includes('admin')) {
return res.status(403).json({ error: 'Forbidden' });
}
const user = await User.findById(userId);
res.json(user);
});
// Good: CASL for complex authorization
import { defineAbility } from '@casl/ability';
const ability = defineAbility((can, cannot) => {
can('read', 'Article');
can('update', 'Article', { authorId: user.id });
cannot('delete', 'Article').because('Not allowed');
});
if (ability.cannot('update', article)) {
throw new ForbiddenError('Cannot update this article');
}
```
### A03: Injection Prevention
```typescript
// Bad: SQL Injection
const query = `SELECT * FROM users WHERE id = ${userId}`;
await db.query(query);
// Good: Parameterized queries (pg)
const { rows } = await pool.query(
'SELECT * FROM users WHERE id = $1',
[userId]
);
// Good: Prisma (auto-parameterized)
const user = await prisma.user.findUnique({
where: { id: userId }
});
// Good: Drizzle (type-safe)
const users = await db.select().from(usersTable).where(eq(usersTable.id, userId));
// Bad: NoSQL Injection (MongoDB)
const user = await User.findOne({ name: req.query.name }); // If name = { $ne: "" }
// Good: Type validation
import { z } from 'zod';
const QuerySchema = z.object({
name: z.string().min(1).max(100)
});
const { name } = QuerySchema.parse(req.query);
const user = await User.findOne({ name });
// Bad: Template injection
const template = `Hello ${userInput}`;
eval(template);
// Good: Safe templating
import Handlebars from 'handlebars';
const template = Handlebars.compile('Hello {{name}}');
const result = template({ name: sanitizedInput });
```
### A04: Cryptographic Failures
```typescript
// Bad: Weak hashing
import crypto from 'crypto';
const hash = crypto.createHash('md5').update(password).digest('hex');
// Good: Argon2 for passwords
import argon2 from 'argon2';
const hash = await argon2.hash(password, {
type: argon2.argon2id,
memoryCost: 65536,
timeCost: 3,
parallelism: 4
});
const valid = await argon2.verify(hash, password);
// Good: bcrypt alternative
import bcrypt from 'bcrypt';
const hash = await bcrypt.hash(password, 12);
const valid = await bcrypt.compare(password, hash);
// Good: Secure random generation
import { randomBytes, randomUUID } from 'crypto';
const token = randomBytes(32).toString('hex');
const id = randomUUID();
// Good: AES-GCM encryption
import { createCipheriv, createDecipheriv, randomBytes, scrypt } from 'crypto';
async function encrypt(text: string, password: string): Promise<string> {
const iv = randomBytes(16);
const key = await new Promise<Buffer>((resolve, reject) => {
scrypt(password, 'salt', 32, (err, key) => {
if (err) reject(err);
else resolve(key);
});
});
const cipher = createCipheriv('aes-256-gcm', key, iv);
const encrypted = Buffer.concat([cipher.update(text, 'utf8'), cipher.final()]);
const authTag = cipher.getAuthTag();
return Buffer.concat([iv, authTag, encrypted]).toString('base64');
}
```
### A05: XSS Prevention
```typescript
// Bad: Direct innerHTML
element.innerHTML = userInput;
// Good: textContent or sanitize
element.textContent = userInput;
// Good: DOMPurify for rich content
import DOMPurify from 'dompurify';
element.innerHTML = DOMPurify.sanitize(userInput);
// React: JSX auto-escapes by default
return <div>{userInput}</div>; // Safe
// Bad: dangerouslySetInnerHTML without sanitization
return <div dangerouslySetInnerHTML={{ __html: userInput }} />;
// Good: Sanitize before using dangerouslySetInnerHTML
return <div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(userInput) }} />;
// Good: CSP Headers (Express)
import helmet from 'helmet';
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", 'data:', 'https:'],
connectSrc: ["'self'", 'https://api.example.com'],
frameSrc: ["'none'"],
objectSrc: ["'none'"]
}
}
}));
```
### A07: Authentication Failures
```typescript
// Good: Secure session configuration (Express)
import session from 'express-session';
app.use(session({
secret: process.env.SESSION_SECRET!,
resave: false,
saveUninitialized: false,
cookie: {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'strict',
maxAge: 3600000 // 1 hour
}
}));
// Good: Rate limiting
import rateLimit from 'express-rate-limit';
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 5,
message: 'Too many login attempts',
standardHeaders: true,
legacyHeaders: false
});
app.post('/login', loginLimiter, loginHandler);
// Good: JWT with proper validation
import jwt from 'jsonwebtoken';
import { z } from 'zod';
const JwtPayloadSchema = z.object({
sub: z.string(),
email: z.string().email(),
roles: z.array(z.string()),
iat: z.number(),
exp: z.number()
});
function verifyToken(token: string): JwtPayload {
const decoded = jwt.verify(token, process.env.JWT_SECRET!, {
algorithms: ['HS256'],
issuer: 'my-app',
audience: 'my-app-users'
});
return JwtPayloadSchema.parse(decoded);
}
```
### A08: Software Integrity
```typescript
// Good: Subresource Integrity (SRI)
<script
src="https://cdn.example.com/lib.js"
integrity="sha384-abc123..."
crossorigin="anonymous"
/>
// Good: Verify package signatures in CI
// package.json
{
"scripts": {
"audit": "npm audit --audit-level=high",
"preinstall": "npx npm-force-resolutions"
}
}
// Good: Avoid eval and Function constructor
// Bad:
eval(userInput);
new Function(userInput)();
// Good: Use safe alternatives
const safeOperations: Record<string, (a: number, b: number) => number> = {
add: (a, b) => a + b,
subtract: (a, b) => a - b
};
const result = safeOperations[operation]?.(a, b);
```
## TypeScript-Specific Security
### Type Safety for Security
```typescript
// Good: Branded types for sensitive data
declare const PasswordBrand: unique symbol;
type Password = string & { [PasswordBrand]: true };
function hashPassword(password: Password): Promise<string> {
return argon2.hash(password);
}
// Can't pass arbitrary strings
const plainPassword = 'secret123';
// hashPassword(plainPassword); // Type error!
const validatedPassword = validatePassword(plainPassword) as Password;
hashPassword(validatedPassword); // OK
// Good: Zod for runtime validation
import { z } from 'zod';
const UserInputSchema = z.object({
email: z.string().email(),
password: z.string().min(12).regex(/[A-Z]/).regex(/[a-z]/).regex(/[0-9]/),
age: z.number().int().positive().max(150)
});
type UserInput = z.infer<typeof UserInputSchema>;
function createUser(input: unknown): User {
const validated = UserInputSchema.parse(input); // Throws on invalid
// validated is now properly typed
return userService.create(validated);
}
```
### Secure API Design
```typescript
// Good: Input validation with error handling
import { z } from 'zod';
import { fromZodError } from 'zod-validation-error';
const CreateOrderSchema = z.object({
items: z.array(z.object({
productId: z.string().uuid(),
quantity: z.number().int().positive().max(100)
})).min(1).max(50),
shippingAddress: z.object({
street: z.string().min(1).max(200),
city: z.string().min(1).max(Related in Security
mac-ops
IncludedComprehensive macOS workstation operations — diagnose kernel panics, identify failing drives, audit launchd startup items, decode wake reasons, triage TCC permission denials, manage APFS snapshots, recover from no-boot. Use for: Mac is slow, slow bootup, won't boot, kernel panic, kernel_task hot, mds_stores CPU, photoanalysisd, cloudd, login loop, gray screen, sleep wake failure, drive failing, IO errors, APFS snapshots eating space, Time Machine local snapshots, Spotlight indexing, launchd, LaunchAgent, LaunchDaemon, login items, TCC permissions, Full Disk Access, Screen Recording denied, Gatekeeper, quarantine, com.apple.quarantine, app is damaged, helper tool, /Library/PrivilegedHelperTools, pmset, wake reasons, dark wake, sysdiagnose, panic.ips, DiagnosticReports, configuration profile, MDM profile, remote diagnostics over SSH.
a11y-audit
IncludedRun accessibility audits on web projects combining automated scanning (axe-core, Lighthouse) with WCAG 2.1 AA compliance mapping, manual check guidance, and structured reporting. Output is configurable: markdown report only, markdown plus machine-readable JSON, or markdown plus issue tracker integration. Use this skill whenever the user mentions "accessibility audit", "a11y audit", "WCAG audit", "accessibility check", "compliance scan", or asks to check a web project for accessibility issues. Also trigger when the user wants to verify WCAG conformance or map findings to a specific standard (CAN-ASC-6.2, EN 301 549, ADA/AODA).
erpclaw
IncludedAI-native ERP system with self-extending OS. Full accounting, invoicing, inventory, purchasing, tax, billing, HR, payroll, advanced accounting (ASC 606/842, intercompany, consolidation), and financial reporting. 413 actions across 14 domains, 43 expansion modules. Constitutional guardrails, adversarial audit, schema migration. Double-entry GL, immutable audit trail, US GAAP.
assess
IncludedAssesses and rates quality 0-10 across multiple dimensions (correctness, maintainability, security, performance, testability, simplicity) with pros/cons analysis. Compares against project conventions and prior decisions from memory. Produces structured evaluation reports with actionable improvement suggestions. Use when evaluating code, designs, architectures, or comparing alternative approaches.
spring-boot-security-jwt
IncludedProvides JWT authentication and authorization patterns for Spring Boot 3.5.x covering token generation with JJWT, Bearer/cookie authentication, database/OAuth2 integration, and RBAC/permission-based access control using Spring Security 6.x. Use when implementing authentication or authorization in Spring Boot applications.
code-hardcode-audit
IncludedDetect hardcoded values, magic numbers, and leaked secrets. TRIGGERS - hardcode audit, magic numbers, PLR2004, secret scanning.