asf-tooling opened a new issue, #1064:
URL: https://github.com/apache/tooling-trusted-releases/issues/1064

   **ASVS Level(s):** L2-only
   
   **Description:**
   
   ### Summary
   The ZIP download endpoint streams an archive of all files in a release 
directory without checking total size, file count, or imposing streaming 
timeouts. For releases with many large files (50,000 files, 20 GB total), this 
causes extended resource consumption during ZIP generation and transfer, 
potentially holding server resources for hours on slow client connections. 
Authentication and rate limiting provide some protection.
   
   ### Details
   The issue exists in `atr/get/download.py` in the `zip_selected()` function. 
ZIP streaming is unbounded in both file count and total size.
   
   ### Recommended Remediation
   Add resource limits before streaming:
   
   ```python
   _MAX_ZIP_FILES = 10000
   _MAX_ZIP_TOTAL_BYTES = 10 * 1024 * 1024 * 1024  # 10 GB
   
   @download.get
   async def zip_selected(
       session: web.Committer,
       project_key: safe.ProjectKey,
       version_key: safe.VersionKey
   ) -> web.QuartResponse:
       """Stream ZIP archive with resource limits."""
       
       # Collect files and track size
       files_to_zip = []
       total_size = 0
       
       for file_path in release_directory.iterdir():
           if len(files_to_zip) >= _MAX_ZIP_FILES:
               return quart.Response(
                   f"Release contains more than {_MAX_ZIP_FILES} files. "
                   f"Please download individual files or contact support.",
                   status=413
               )
           
           file_size = file_path.stat().st_size
           total_size += file_size
           
           if total_size > _MAX_ZIP_TOTAL_BYTES:
               return quart.Response(
                   f"Release total size exceeds {_MAX_ZIP_TOTAL_BYTES // 
(1024**3)} GB. "
                   f"Please download individual files or contact support.",
                   status=413
               )
           
           files_to_zip.append(file_path)
       
       # Log metrics for monitoring
       log.info(
           "Starting ZIP download",
           project=project_key,
           version=version_key,
           file_count=len(files_to_zip),
           total_size=total_size
       )
       
       # Stream ZIP with collected files
       return await stream_zip(files_to_zip)
   ```
   
   **Alternative approach for very large releases:**
   Provide manifest file with individual download links instead of ZIP 
streaming:
   
   ```python
   if len(files_to_zip) > _MAX_ZIP_FILES or total_size > _MAX_ZIP_TOTAL_BYTES:
       # Generate manifest with download links
       manifest = generate_download_manifest(files_to_zip)
       return web.TextResponse(manifest, mimetype='text/plain')
   ```
   
   ### Acceptance Criteria
   - [ ] File count limit enforced (_MAX_ZIP_FILES)
   - [ ] Total size limit enforced (_MAX_ZIP_TOTAL_BYTES)
   - [ ] 413 status returned with helpful message when limits exceeded
   - [ ] Metrics logged for monitoring (file count, total size)
   - [ ] Unit tests verify limits are enforced
   - [ ] Integration tests verify large releases handled correctly
   - [ ] OR: Manifest-based approach implemented for large releases
   - [ ] Documentation updated with ZIP download limits
   
   ### References
   - Source reports: L2:15.1.3.md
   - Related findings: FINDING-052
   - ASVS sections: 15.1.3
   - CWE: CWE-770
   
   ### Priority
   Medium
   
   ---


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to