Skip to content

Security/3.4.0#464

Open
ronaldsg20 wants to merge 4 commits into
3.4.0from
security/3.4.0
Open

Security/3.4.0#464
ronaldsg20 wants to merge 4 commits into
3.4.0from
security/3.4.0

Conversation

@ronaldsg20
Copy link
Copy Markdown
Member

📌 Summary

Adds input-size caps, duplicate rejection, concurrency control, and per-address txid/UTXO row limits to the /addresses-info and /utxo endpoints to prevent resource exhaustion attacks. Also fixes three acceptance-test failures caused by unstubbed service dependencies hitting MongoDB.

🔍 Description

What was changed

New utilities

  • src/config/limits.ts — centralised, env-overridable constants (ADDRESS_LIST_MAX_ITEMS, UTXO_RESPONSE_MAX_ROWS, ADDRESS_INFO_MAX_TXIDS, PROVIDER_CONCURRENCY, REJECT_DUPLICATE_ADDRESSES).
  • src/utils/address-patterns.ts — single source of truth for BTC, EVM, and combined address regex patterns; replaces inline duplicated patterns across controllers and models.
  • src/utils/address-list-validation.ts — shared guard that raises 422 UnprocessableEntity when the list exceeds maxItems or contains duplicate addresses.
  • src/utils/concurrency.tswithConcurrency helper that processes items in bounded batches instead of an unbounded Promise.all, limiting simultaneous upstream calls.

Controller hardening

  • AddressesInfoController — now validates the list, fans out with withConcurrency, and caps txids per address at ADDRESS_INFO_MAX_TXIDS before serialisation.
  • UtxoController — validates the list, fans out with withConcurrency, and rejects responses that exceed UTXO_RESPONSE_MAX_ROWS with 413 PayloadTooLarge.
  • Both controllers switched from callback-style Promise.all + .then/.catch chains to async/await.

Why it was changed

The /addresses-info and /utxo endpoints accepted arbitrarily long address lists and issued a separate upstream HTTP call per address with no concurrency ceiling, creating a straightforward amplification vector (one small API request → N simultaneous Blockbook calls). Duplicate addresses compounded the issue. The acceptance test failures were pre-existing regressions introduced when test setup did not stub all service dependencies.

Scope of impact

All changes are additive or are refactors of existing validation logic. Default limits are generous (ADDRESS_LIST_MAX_ITEMS=50, UTXO_RESPONSE_MAX_ROWS=1000, ADDRESS_INFO_MAX_TXIDS=100, PROVIDER_CONCURRENCY=5) and can be tuned via environment variables without a code change.

🧪 How to Test

Unit tests

npm run unit-test

Acceptance tests (all should pass, 0 failing)

npm run acceptance-test
  • I have tested this locally
  • Unit / integration tests added or updated

🧠 Known Issues / Limitations

  • withConcurrency processes items in sequential chunks of size PROVIDER_CONCURRENCY; truly interleaved concurrency (e.g. a semaphore) would give better throughput for large lists but is not required at current scale.
  • ADDRESS_LIST_MAX_ITEMS defaults to 50; downstream callers that currently send larger lists will receive 422 — a coordinated front-end update may be needed.
  • The UTXO row cap returns 413 PayloadTooLarge after all upstream calls complete; future work could short-circuit earlier once the threshold is reached.

📎 Related task

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 1, 2026

Dependency Review

The following issues were found:

  • ❌ 1 vulnerable package(s)
  • ✅ 0 package(s) with incompatible licenses
  • ✅ 0 package(s) with invalid SPDX license definitions
  • ✅ 0 package(s) with unknown licenses.
  • ⚠️ 5 packages with OpenSSF Scorecard issues.

View full job summary

…failures

    I've defined ADDRESS_LIST_MAX_ITEMS, UTXO_RESPONSE_MAX_ROWS,
    ADDRESS_INFO_MAX_TXIDS and PROVIDER_CONCURRENCY env variables in
    order to set an upper bound of on the requests and avoid external
    provider/services saturation
@alexjavabraz alexjavabraz marked this pull request as draft June 1, 2026 13:56
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.

1 participant