diff --git a/skills/app-security/SKILL.md b/skills/app-security/SKILL.md new file mode 100644 index 0000000..2f3b22b --- /dev/null +++ b/skills/app-security/SKILL.md @@ -0,0 +1,98 @@ +--- +name: app-security +description: > + Full-stack application and API security hardening: Four-Pillar upload defense, + SSRF prevention, input boundary clamping, IDOR elimination, and secret masking. + Use when creating or auditing API routes, handling uploads, making outbound requests, + or preparing pre-release security verification. +concerns: [security] +--- + +# Application Security Hardening + +Enforces defensive boundaries across the API membrane, eliminating exploit vectors, path traversals, SSRF risks, IDOR vulnerabilities, and payload exhaustion. + +```mermaid +flowchart LR + A["Inbound Request"] --> B["1. Membrane Clamping
(Schema & Bound Validation)"] + B --> C["2. Four-Pillar Uploads
(Size, Ext, Magic, Path)"] + C --> D["3. Outbound SSRF Guard
(Loopback/Metadata Block)"] + D --> E["4. Secret Masking
(Zero Token Sediment)"] +``` + +--- + +## Phase 0: Setup and Protocols + +1. Review reference playbooks: + - [references/app-hardening-playbook.md](references/app-hardening-playbook.md) for concrete TypeScript/Python code patterns and boundary clamps. + - [references/review-checklist.md](references/review-checklist.md) for pre-release OWASP verification checks. +2. Invariants: + - Every input payload must be typed and bounded. + - Every state mutation must verify session identity and tenant ownership. + - Outbound HTTP fetches must never touch private/loopback networks. + +--- + +## Phase 1: Ingest and Check + +1. **Surface Identification**: + - Inbound API routes (REST, GraphQL, RPC handlers). + - File/document ingestion and attachment endpoints. + - Outbound network calls (webhooks, URL unfurlers, external data scrapers). + - Data persistence operations and logging sinks. +2. **Access Control Check**: + - Confirm identity is derived from verified server sessions/tokens, never trusted client parameters (`userId`, `orgId`). + - Confirm entity queries enforce ownership: verify record exists AND belongs to the authenticated caller before mutating. + +--- + +## Phase 2: Processing (Core Logic) + +### Step 1: Input Boundaries & Membrane Clamping +- Never accept arbitrary, unvalidated request dictionaries. Model all payloads using strict schemas (e.g. Pydantic, Zod). +- Enforce hard string limits: + - Text prompts / message content: Max 50,000 characters. + - Titles / Names: Max 100–200 characters. + - Pagination limits: Clamped to `1 <= limit <= 50`. + - Batch arrays: Clamped to max 100–200 items. +- Sanitize entity and path identifiers against path traversal tokens (`../`, `..\\`). + +### Step 2: Four-Pillar Upload Defense +When handling file or media uploads: +1. **Size Bounds**: Reject payloads exceeding size thresholds (e.g., 100MB for docs; 5MB for images). +2. **Blocked Extensions**: Reject executable and script formats (`.exe`, `.bat`, `.sh`, `.svg`, `.html`, `.php`). +3. **Magic Byte Inspection**: Inspect file headers to detect disguised binaries (PE `MZ`, ELF, Mach-O). +4. **Path Traversal Defense**: + - Sanitize original filenames (strip path separators and non-printable characters). + - Write files strictly to designated, isolated upload roots with unique IDs (e.g. UUID filenames). + +### Step 3: Outbound SSRF Guard +Before executing outbound HTTP requests (scraping, webhooks): +- Validate target URLs against an allowlist or safety filter. +- Block loopback addresses (`127.0.0.1`, `localhost`, `::1`), RFC 1918 private subnets (`10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`), and cloud metadata services (`169.254.169.254`). +- Restrict allowed protocols strictly to `http` and `https`. + +### Step 4: Secret Masking & Error Shielding +- Scrub Authorization tokens (`Bearer ***`), provider API keys, and sensitive credentials from logs, database traces, and telemetry. +- In public HTTP error responses, return clean structured error objects with opaque error codes; never leak internal filesystem paths, environment variables, or stack traces. + +--- + +## Phase 3: The System One Balance Pass + +- **Augment, Don't Handcuff**: + - Do NOT break local development workflows: allow local mock endpoints and fixture testing in non-production test environments. + - Keep security checks non-intrusive during prototyping; enforce strictly at boundaries and pre-release gates. + - Avoid noisy confirmation warnings for routine safe operations. + +--- + +## Phase 4: Output Execution & Verification + +1. Run verification checks from [references/review-checklist.md](references/review-checklist.md). +2. Provide a security verification summary detailing: + - Bound clamps applied to route schemas. + - Upload filters active (size, extension, magic bytes, safe path). + - SSRF protection status on outbound calls. + - Secret scrubbing confirmation. diff --git a/skills/app-security/references/app-hardening-playbook.md b/skills/app-security/references/app-hardening-playbook.md new file mode 100644 index 0000000..0aebad8 --- /dev/null +++ b/skills/app-security/references/app-hardening-playbook.md @@ -0,0 +1,160 @@ +# Full-Stack Application Security Hardening Playbook + +This high-level guide provides a reusable, standardized protocol for auditing and securing full-stack applications (Next.js, Node.js, Express, etc.). + +--- + +## Phase 1: Endpoint & Access Control (Preventing IDOR) + +### 1. The Multi-Tenant Ownership Rule +Every state-changing API request (`POST`, `PUT`, `PATCH`, `DELETE`) and private resource read (`GET`) must establish identity via the server session—never by trusting client parameters. + +#### Never Trust Client User IDs: +```typescript +// ❌ Vulnerable (attacker can pass any userId in body) +const { title, userId } = await req.json(); +await db.resource.create({ data: { title, userId } }); + +// ✅ Secure (always bind to verified session) +const session = await getServerSession(authOptions); +if (!session?.user?.id) return unauthorized(); +await db.resource.create({ data: { title, userId: session.user.id } }); +``` + +#### Verify Resource Ownership Before Mutation: +```typescript +// Verify target record exists AND belongs to the caller +const item = await db.resource.findUnique({ where: { id } }); +if (!item) return notFound(); +if (item.userId !== session.user.id) return forbidden(); +``` + +#### Lock Down Sensitive Data Endpoints: +* Strip internal data (emails, password hashes, roles, permissions) from public query endpoints. +* Never allow query flags like `?includePrivate=true` unless the caller has verified ownership or administrative authorization for that account. + +--- + +## Phase 2: Input Boundaries & Payload Sanitization + +### 1. Enforce Hard Limits on Every Field +Unbounded input strings can cause database exhaustion, buffer overruns, or CPU denial-of-service (e.g., Bcrypt hashing huge strings). + +| Field Type | Recommended Hard Bound | Rationale | +| :--- | :--- | :--- | +| **Passwords** | Min 8 chars, Max 72–100 chars | Bcrypt truncates or burns excessive CPU beyond 72 bytes | +| **Emails** | Max 254 chars | Standard RFC 5321 length; prevents regex DoS | +| **Titles / Names** | Max 100–200 chars | Prevents UI overflow and DB memory bloat | +| **Descriptions / Content** | Max 2,000–50,000 chars | Prevents payload bombing | +| **Pagination limit** | Clamped to `1 <= limit <= 50` | Prevents querying the entire table at once | + +### 2. JSON & Batch Array Clamping +When accepting array batches (e.g., bulk updating nodes or items), enforce an explicit upper limit (e.g., max 200–500 items per request). + +--- + +## Phase 3: Safe File & Document Upload Architecture + +If an application accepts images, PDFs, or documents, implement the **Four-Pillar Upload Defense**: + +```mermaid +flowchart LR + A["File Upload"] --> B["1. Size Check"] + B --> C["2. Extension & MIME Allowlist"] + C --> D["3. Magic Bytes Inspection"] + D --> E["4. Filename Sanitization & Storage"] +``` + +### 1. Size Caps: +* Check file size before buffering: images (max 2–5MB), documents (max 10MB). +* Terminate stream early if incoming chunks exceed the configured byte threshold. + +### 2. Strict MIME & Extension Allowlists: +* **Allowed:** `image/jpeg` (`.jpg`, `.jpeg`), `image/png` (`.png`), `image/webp` (`.webp`), `application/pdf` (`.pdf`), `application/json` (`.json`), `text/markdown` (`.md`). +* **Strictly Blocked:** `.exe`, `.bat`, `.sh`, `.php`, `.js`, `.html`, `.svg` (SVGs can embed `