# Protection against malicious code (input validation, dependency integrity)

- **Pattern:** `ab-001567` (`gov-cmmc-level-1.system-integrity.malicious-code`)
- **Severity:** critical
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001567
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001567)

## Why it matters

CMMC 2.0 SI.L1-3.14.2 (NIST 800-171r2 3.14.2) requires protection against malicious code at appropriate locations in organizational systems. The primary code-level attack vectors are SQL injection via string-concatenated queries, XSS via raw innerHTML insertion of user content, and dependency confusion via uncontrolled registry sources. A single SQL injection point in a route that handles FCI gives an attacker arbitrary read/write access to the database. CWE-20 (Improper Input Validation), CWE-89 (SQL Injection), and OWASP A03 (Injection) all apply. Zod-validated API routes using ORM queries eliminate both injection classes simultaneously.

## Severity rationale

Critical because SQL injection in an FCI-handling API route gives an unauthenticated or low-privileged attacker direct read/write access to the entire database.

## Remediation

Validate every API input with Zod before it touches the database or the DOM. Use Prisma or parameterized queries — never string-concatenate user input into SQL:

```ts
// lib/validation/search.ts
import { z } from 'zod'
export const searchSchema = z.object({
  query: z.string().min(1).max(200).trim(),
  category: z.enum(['documents', 'users', 'contracts']).optional(),
})

// app/api/search/route.ts
export async function POST(req: Request) {
  const result = searchSchema.safeParse(await req.json())
  if (!result.success) return Response.json({ error: 'Invalid search parameters' }, { status: 400 })

  const { query, category } = result.data
  // Prisma parameterizes automatically — no injection possible
  const docs = await prisma.document.findMany({
    where: { title: { contains: query, mode: 'insensitive' }, ...(category ? { category } : {}) },
  })
  return Response.json(docs)
}
```

For React components, prefer `{userContent}` interpolation — React escapes HTML automatically. When HTML rendering is unavoidable, install `dompurify` and sanitize before insertion. Never use `dangerouslySetInnerHTML={{ __html: userContent }}` without prior sanitization.

## Detection

- **ID:** `malicious-code`
- **Severity:** `critical`
- **CMMC Practice:** SI.L1-3.14.2
- **What to look for:** Examine input validation coverage — all user inputs must be validated server-side. Look for schema validation libraries (zod, joi, yup, valibot) used in API route handlers. Check for SQL injection vectors: raw SQL with user input, string-concatenated queries, or ORM usage without parameterization. Look for XSS vectors: raw innerHTML assignments with unsanitized content, or template literals inserting user content into HTML strings. Check for a committed lock file (dependency integrity). Look for dependencies from trusted registries only (no unusual registry overrides in `.npmrc`). Check for CSP headers that reduce XSS impact.
- **Pass criteria:** Count all API routes and check each for server-side input validation. At least 90% of API routes validate input server-side using a schema library (Zod, Joi, Yup). No more than 0 raw innerHTML assignments with unvalidated user content. Database queries use parameterized statements or ORM. Report: "X of Y API routes have server-side input validation."
- **Fail criteria:** API routes accept user input without server-side validation. SQL queries built with string concatenation from user input. User-provided HTML inserted into the DOM without sanitization. No lock file. Unusual registry configurations in `.npmrc`.
- **Skip (N/A) when:** Never — malicious code protection is a core CMMC Level 1 requirement.
- **Detail on fail:** Identify the specific injection vector or validation gap. Example: `"app/api/search/route.ts: query directly concatenated into SQL string — SQL injection possible. No input validation found in any API route. No lock file committed."` Keep under 500 characters.
- **Remediation:** Validate all inputs and use safe query patterns:

  ```ts
  // lib/validation/search.ts
  import { z } from 'zod'

  export const searchSchema = z.object({
    query: z.string().min(1).max(200).trim(),
    category: z.enum(['documents', 'users', 'contracts']).optional()
  })

  // app/api/search/route.ts
  import { searchSchema } from '@/lib/validation/search'

  export async function POST(req: Request) {
    const body = await req.json()
    const result = searchSchema.safeParse(body)

    if (!result.success) {
      return Response.json({ error: 'Invalid search parameters' }, { status: 400 })
    }

    const { query, category } = result.data

    // Use ORM (Prisma) — parameterized queries prevent SQL injection automatically
    const docs = await prisma.document.findMany({
      where: {
        title: { contains: query, mode: 'insensitive' },
        ...(category ? { category } : {})
      }
    })

    return Response.json(docs)
  }
  ```

  For rendering user-provided content in React, prefer plain text interpolation (React escapes automatically) over innerHTML. When HTML rendering is unavoidable, use DOMPurify to sanitize before insertion:

  ```ts
  // Install: npm install dompurify @types/dompurify
  import DOMPurify from 'dompurify'

  // Safe: React escapes this automatically
  <div>{userTextContent}</div>

  // When HTML rendering is unavoidable, sanitize first:
  const cleanHtml = DOMPurify.sanitize(userHtmlContent)
  // Then insert the sanitized result — never insert raw user HTML
  ```

## External references

- cmmc SI.L1-3.14.2
- cwe CWE-20
- cwe CWE-89
- owasp A03
- nist SP-800-171 3.14.2

Taxons: injection-and-input-trust, regulatory-conformance

HTML version: https://auditbuffet.com/patterns/ab-001567
