fix: use bounded read for workflow catalog HTTP responses - #3766
Open
Quratulain-bilal wants to merge 2 commits into
Open
Quratulain-bilal wants to merge 2 commits into
Quratulain-bilal wants to merge 2 commits into
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Bounds workflow and step catalog HTTP responses to 1 MiB, mitigating memory-exhaustion risks.
Changes:
- Uses
read_response_limitedfor both catalog fetch paths. - Applies
MAX_JSON_METADATA_BYTESas the response limit.
Show a summary per file
| File | Description |
|---|---|
src/specify_cli/workflows/catalog.py |
Adds bounded reads for workflow and step catalogs. |
Review details
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comments suppressed due to low confidence (1)
src/specify_cli/workflows/catalog.py:1219
- Please cover the step-catalog fetch path with an oversized streamed response and assert
StepCatalogError. StepCatalog has separate fetch/cache handling, and its current fetch tests also exit before reading the body, so they do not verify that this call site actually enforces the new limit.
data = json.loads(
read_response_limited(resp, max_bytes=MAX_JSON_METADATA_BYTES).decode("utf-8")
- Files reviewed: 1/1 changed files
- Comments generated: 1
- Review effort level: Medium
mnriem
requested changes
Jul 27, 2026
mnriem
left a comment
Collaborator
There was a problem hiding this comment.
Please address Copilot feedback
The workflow catalog fetch used unbounded resp.read() to read HTTP responses into memory. A malicious or misconfigured catalog server could return an arbitrarily large response causing OOM. Replace with read_response_limited() capped at MAX_JSON_METADATA_BYTES (1 MiB) at both call sites, consistent with how other JSON fetch paths in the codebase enforce bounded reads.
Quratulain-bilal
force-pushed
the
fix/unbounded-workflow-catalog-response
branch
from
July 27, 2026 22:15
291d343 to
5c2087c
Compare
Collaborator
|
Please resolve conflicts |
Contributor
There was a problem hiding this comment.
Review details
Comments suppressed due to low confidence (6)
tests/test_workflows.py:6843
- This patch target does not exist: the workflow fetch passes
MAX_JSON_CATALOG_BYTEStoread_response_limited. As written, the test fails during setup rather than validating recovery after an oversized response.
"specify_cli.workflows.catalog.MAX_JSON_METADATA_BYTES", 512
tests/test_workflows.py:7675
workflows.catalogexposesMAX_JSON_CATALOG_BYTES, notMAX_JSON_METADATA_BYTES, so this monkeypatch fails withAttributeErrorbefore exercisingStepCatalog._fetch_single_catalog. Patch the constant actually used by that fetch.
"specify_cli.workflows.catalog.MAX_JSON_METADATA_BYTES", 512
tests/test_workflows.py:7727
- This test patches a nonexistent module attribute and therefore cannot verify that a healthy step catalog still works after rejection. The production bounded read uses
MAX_JSON_CATALOG_BYTES.
"specify_cli.workflows.catalog.MAX_JSON_METADATA_BYTES", 512
tests/test_workflows.py:7666
- The step-catalog fetch is bounded by
MAX_JSON_CATALOG_BYTES, not the metadata limit. Update the docstring so it documents the actual regression contract.
MAX_JSON_METADATA_BYTES instead of reading unbounded into memory."""
tests/test_workflows.py:6791
workflows.catalogimportsMAX_JSON_CATALOG_BYTES, notMAX_JSON_METADATA_BYTES, somonkeypatch.setattrraisesAttributeErrorand this regression test never reaches the fetch. Patch the catalog limit used by the production call instead.
This issue also appears in the following locations of the same file:
- line 6843
- line 7675
- line 7727
"specify_cli.workflows.catalog.MAX_JSON_METADATA_BYTES", 512
tests/test_workflows.py:6782
- The implementation now uses the catalog-specific 8 MiB ceiling, so this docstring names the wrong constant and incorrectly describes the behavior under test.
This issue also appears on line 7666 of the same file.
MAX_JSON_METADATA_BYTES instead of reading unbounded into memory."""
- Files reviewed: 1/1 changed files
- Comments generated: 0 new
- Review effort level: Medium
Collaborator
|
Please address test & lint errors |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The workflow catalog fetch (
WorkflowCatalog._fetch_single_catalogandStepCatalog._fetch_single_catalog) used unboundedresp.read()to read HTTP responses into memory. A malicious or misconfigured catalog server could return an arbitrarily large response causing OOM.Changes
src/specify_cli/workflows/catalog.py(lines 541, 1214): Replacedresp.read()withread_response_limited(resp, max_bytes=MAX_JSON_METADATA_BYTES)capped at 1 MiB at both call sites, consistent with how other JSON fetch paths in the codebase enforce bounded reads.Testing
All 176 tests in
tests/workflows/pass after the fix.Security Impact
This is a Medium severity fix - it closes a potential memory exhaustion vector against the workflow catalog fetch endpoint.