Skip to content

fix: validate API path parameters and rate-limit artist requests (#987) - #1043

Merged
DevMuhdishaq merged 1 commit into
Dfunder:mainfrom
danieloche635-bit:fix/987-route-param-validation
Oct 19, 2026
Merged

DevMuhdishaq merged 1 commit into
Dfunder:mainfrom
danieloche635-bit:fix/987-route-param-validation

Conversation

@danieloche635-bit

Copy link
Copy Markdown
Contributor

Summary

Closes #987.

Every dynamic path parameter is now validated at the shared HTTP boundary before a request leaves the browser, and artist GET endpoints are rate-limited. Traversal, encoded separators and SQL/NoSQL payloads are rejected with a 400 ApiError; the artist budget returns 429.

This repository is a Vite SPA and has no api/artist/[id].tsx, api/marketplace/[id].tsx or api/portfolio/[id].tsx server routes (and no database layer), so the fix is applied where it is enforceable client-side: the shared axios client that every feature uses. Strict artist-id helpers (validateArtistId / assertValidArtistId) are exported for the API/server adapters. Server-side validation and parameterised queries remain mandatory and are called out in the module docs.

Changes

  • src/services/requestValidation.ts (new)
    • validateRequestPath(url) inspects the raw path before URL can resolve dot segments, so /../ and %2e%2e%2f are caught rather than normalised away.
    • Rejects literal and encoded traversal (.., %2F, %5C, %00), protocol-relative URLs (//evil.example.com), malformed percent-encoding, and characters outside a conservative token allowlist.
    • Rejects SQL/NoSQL payloads such as 1' OR '1'='1, 1;DROP TABLE, 1--, /*comment*/ and {"$ne": null}.
    • validateArtistId / assertValidArtistId: positive integer or RFC 4122 UUID (versions 1-5).
    • validateMarketplaceId / validatePortfolioId: safe single-segment resource ids.
    • checkRequestRateLimit: fixed-window limit of 30 GET requests/minute for the profiles, artists and artist endpoint families, with a retry-after message.
  • src/services/http.ts
    • The request interceptor rejects unsafe paths with ApiError(400, 'VALIDATION_FAILED') and exhausted budgets with ApiError(429, 'RATE_LIMITED') before the adapter/network is reached.
    • The response interceptor now preserves an ApiError produced by the request guards instead of relabelling it as NETWORK_ERROR.
  • Tests
    • src/services/requestValidation.test.ts — 11 tests for path safety, traversal/injection payloads, strict artist/resource ids and rate-limit windows.
    • src/services/requestValidation.http.test.ts — 4 integration tests proving malicious requests never reach the adapter and that the 31st artist request returns 429.

Acceptance criteria

  • api/artist/[id].tsx validates the id parameter format — strict validateArtistId (positive integer or UUID) is provided and exported for the API layer
  • Invalid IDs return 400 Bad Request with a clear message
  • SQL injection attempts are blocked
  • Path traversal attempts are blocked
  • Test asserts validation blocks malicious inputs
  • All artist/marketplace/portfolio API calls validate their parameters at the shared HTTP boundary
  • No unvalidated dynamic path parameters remain in the API client

Testing

npx vitest run src/services/requestValidation.test.ts src/services/requestValidation.http.test.ts
# 2 files passed, 15 tests passed

npx eslint <changed files>
# clean

npx prettier --check <changed files>
# clean

npm run type-check
# No errors reported in any changed file.

Pre-existing failure on main (not introduced by this PR): src/stores/useUiStore.ts has a merge syntax error, so the older src/services/http.test.ts suite cannot load. The integration test here mocks that unrelated store so it can exercise the real interceptor chain. The same pre-existing breakage also exists in src/features/messaging/index.ts, src/components/ui/Skeleton.tsx and vite.config.ts.

Security note

Client-side rate limiting is bypassable by an attacker who controls the client; it is included as defence in depth and to stop request storms. The API must also enforce per-IP/per-account limits and use parameterised queries.

…nder#987)

Validate every dynamic path segment at the shared HTTP boundary, rejecting
traversal, encoded separators and SQL/NoSQL payloads before a request leaves
the browser. Add strict artist-id (positive integer/UUID) helpers and a
30-requests/minute guard for artist GET endpoints.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
@drips-wave

drips-wave Bot commented Oct 19, 2026

Copy link
Copy Markdown

@danieloche635-bit Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@DevMuhdishaq
DevMuhdishaq merged commit a7c9470 into Dfunder:main Oct 19, 2026
0 of 3 checks passed
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.

Governance propose lacks minimum deposit

2 participants