Protection against malicious code (input validation, dependency integrity)
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:
// 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:
// 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:
// 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:2.0 · SI.L1-3.14.2 — Malicious Code Protection
- cwe · CWE-20 — Improper Input Validation
- cwe · CWE-89 — SQL Injection
- owasp:2021 · A03 — Injection
- nist:rev2 · SP-800-171 3.14.2 — Provide protection from malicious code at appropriate locations
Taxons
History
- 2026-04-18·v1.0.0·Initial import from gov-cmmc-level-1·automated