Skip to content

fix: add finite number validation - #1246

Merged
ferhatelmas merged 1 commit into
masterfrom
ferhat/finite
Jul 21, 2026
Merged

fix: add finite number validation#1246
ferhatelmas merged 1 commit into
masterfrom
ferhat/finite

Conversation

@ferhatelmas

Copy link
Copy Markdown
Member

What kind of change does this PR introduce?

Bug fix

What is the current behavior?

AJV coercion (i.e. Infinity, 1e999) skips limit checks.

What is the new behavior?

Add finite check and reject them.
It's mostly relevant for S3 routes but hardened it in all routes.
Strip finite keyword from from OpenAPI since it's a runtime specific and not compatible.

Additional context

Related to #1237

@ferhatelmas
ferhatelmas requested a review from a team as a code owner July 20, 2026 16:22
Copilot AI review requested due to automatic review settings July 20, 2026 16:22

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Comment thread src/http/finite.test.ts Fixed
Comment thread src/http/finite.test.ts Fixed
@coveralls

coveralls commented Jul 20, 2026

Copy link
Copy Markdown

Coverage Report for CI Build 29829824081

Coverage increased (+0.1%) to 79.789%

Details

  • Coverage increased (+0.1%) from the base build.
  • Patch coverage: 1 uncovered change across 1 file (20 of 21 lines covered, 95.24%).
  • 18 coverage regressions across 2 files.

Uncovered Changes

File Changed Covered %
src/http/finite.ts 18 17 94.44%
Total (4 files) 21 20 95.24%

Coverage Regressions

18 previously-covered lines in 2 files lost coverage.

File Lines Losing Coverage Coverage
src/internal/http/agent.ts 17 32.56%
src/http/routes/s3/index.ts 1 82.99%

Coverage Stats

Coverage Status
Relevant Lines: 12785
Covered Lines: 10647
Line Coverage: 83.28%
Relevant Branches: 7476
Covered Branches: 5519
Branch Coverage: 73.82%
Branches in Coverage %: Yes
Coverage Strength: 431.96 hits per line

💛 - Coveralls

strip it from OpenAPI

Signed-off-by: ferhat elmas <elmas.ferhat@gmail.com>
@ferhatelmas

Copy link
Copy Markdown
Member Author

@claude review always

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't find any additional bugs beyond what the automated review covered, but this PR introduces a new custom AJV keyword (finite) wired into the core validator construction for both the public and admin Fastify apps and the standalone S3 router's AJV instance, and applies it across roughly 30 route schemas (S3, iceberg, vector, buckets, admin tenants, pprof). Given the security-relevant nature of the fix (closing a validation-bypass allowing Infinity/1e999 to skip limit checks) and the breadth of touched routes, this is worth a human look rather than a bot approval.

Extended reasoning...

Overview

This PR adds a shared src/http/finite.ts module exposing an AJV keyword (finite) that rejects non-finite numeric values after AJV's type coercion, plus a stripFiniteKeyword/finiteSwaggerTransform pair to remove the internal keyword from generated OpenAPI docs. It wires this keyword into three separate AJV instances: the public app (app.ts), the admin app (admin-app.ts), and the standalone S3 command router's dedicated AJV compiler (s3/router.ts). It then annotates ~30 numeric schema fields across bucket, object, iceberg, S3, and admin/tenant routes with finite: true, and separately hardens the vector route's no-coercion AJV compiler with strictNumbers: true.

Security risks

This is itself a security hardening fix: AJV's coerceTypes will coerce string inputs like "Infinity"" or "1e999"into numericInfinity, which then bypasses minimum/maximumbound checks (e.g. file size limits, pagination limits, multipart part numbers, tenant resource limits). The fix is narrowly scoped to validation and doesn't introduce new attack surface itself, but because it changes validation behavior on security-relevant limits across many endpoints, a regression (e.g. a route that should reject non-finite values but wasn't annotated, or unexpected interaction withnullable`/coercion) could silently reopen the original bypass on just that route.

Level of scrutiny

Given the change touches shared validation plumbing (three separate AJV instantiation points) and is applied broadly rather than to a single isolated route, this warrants more than a rubber-stamp pass — a human should confirm the keyword is applied consistently to all the limit-bearing fields it's meant to cover (e.g. I'd want a second pair of eyes checking for any numeric limit field that may have been missed) and that the OpenAPI-stripping logic can't leak the internal keyword in edge cases (e.g. schemas with ``/allOf composition it wasn't tested against).

Other factors

The PR ships with thorough test coverage (new finite.test.ts, finite-routes.test.ts, and per-route assertions in existing route test suites), and Coveralls reports coverage increased with only one uncovered line. The CodeQL "reflected XSS" alerts are on finite.test.ts inside a test helper that builds a Fastify inject() URL from a loop variable for local test requests — not a real HTTP response reflecting user input — so those read as false positives and don't change my assessment.

@ferhatelmas
ferhatelmas merged commit 6b7f85d into master Jul 21, 2026
26 of 27 checks passed
@ferhatelmas
ferhatelmas deleted the ferhat/finite branch July 21, 2026 12:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants