{"id":"GHSA-4v2w-w6g6-f8f8","kind":"vulnerability","aliases":["GHSA-4v2w-w6g6-f8f8"],"related":[],"title":"Possible DoS vulnerability in Active Storage proxy mode via storage errors during streaming","description":"### Impact\nWhen Active Storage serves a file through its proxy controllers, `ActiveStorage::Streaming#send_blob_stream` handles an error from the storage service by calling `head` to send a 404 or 500 response. If the error occurs after the first chunk has been written, the response is already committed, and `head` replaces the response body while the server is still reading the original `ActionController::Live` buffer. That buffer is never closed, so the server thread handling the request blocks until the process restarts. Repeated failed downloads could exhaust the server's threads, possibly resulting in a DoS vulnerability.\n\nApplications are affected when they store files on a service that streams a download in several requests, such as Amazon S3, an S3-compatible service or Google Cloud Storage, and draw Active Storage's default routes. The proxy routes are drawn whether or not proxy mode is the default for the application. A file deleted while it is being served, or any other storage error partway through a download, triggers the condition.\n\n### Details\nA storage error raised before the response is committed still produces a 404 or 500 response. After the fix, a storage error raised after the response is committed is re-raised instead, so the server closes the streamed response and releases the thread; the client receives a truncated body, and the exception reaches the application's error reporting.\n\n### Releases\nThe fixed releases are available at the normal locations.\n\nPatches for those who cannot upgrade at once:\n- 8.1: https://github.com/rails/rails/commit/3c67a693fb21870ecb1222e3da59d5c491a62009.patch\n- 8.0: https://github.com/rails/rails/commit/655b4442de136a3701334607f634d698bf9d5b82.patch\n\n### Credit\nThis issue was found by the Anthropic OSS Scanner (ANT-2026-FMPUMYTB).","summary":"When Active Storage streams a file through its proxy routes and the storage service fails after the response has started, the server thread blocks until restart. Repeated failed downloads can exhaust server threads and cause a denial of service.","severity":"medium","cvss":5.3,"epss":null,"exploited":false,"exploited_at":null,"products":[{"name":"activestorage","fixed":["8.1.4.1"],"affected":">= 8.1, < 8.1.4.1","ecosystem":"rubygems"},{"name":"activestorage","fixed":["8.0.5.2"],"affected":">= 8.0, < 8.0.5.2","ecosystem":"rubygems"}],"ecosystems":["rubygems"],"tags":["activestorage","cwe-772","google-cloud-storage","package","rails","ruby","s3"],"not_affected_if":["no-proxy-routes","non-streaming-storage"],"how_to_check":"- Check the Rails version in the Gemfile.lock for `activestorage`\n- Confirm the app stores files on S3, an S3-compatible service or Google Cloud Storage\n- Confirm the app draws Active Storage's default routes","fix":"- activestorage `8.1.4.1` for the 8.1 line\n- activestorage `8.0.5.2` for the 8.0 line\n- Patches for those who cannot upgrade at once are linked in the advisory (commits 3c67a693 for 8.1 and 655b4442 for 8.0)","status":"open","published_at":"2026-11-04T03:02:00+00:00","first_seen_at":"2026-11-09T22:53:29+00:00","triaged_at":"2026-11-09T22:56:30+00:00","updated_at":"2026-11-09T22:56:30+00:00","category":"package","confidence":0.8,"triage":{"at":"2026-11-09T22:56:30Z","model":"claude-haiku-5-5","output":{"fix":"- activestorage `8.1.4.1` for the 8.1 line\n- activestorage `8.0.5.2` for the 8.0 line\n- Patches for those who cannot upgrade at once are linked in the advisory (commits 3c67a693 for 8.1 and 655b4442 for 8.0)","reach":"internet","title":"Rails Active Storage: storage errors mid-download can exhaust server threads","impact":"low","summary":"When Active Storage streams a file through its proxy routes and the storage service fails after the response has started, the server thread blocks until restart. Repeated failed downloads can exhaust server threads and cause a denial of service.","audience":"developers","category":"package","nicknames":[],"who_cares":["rails","activestorage","ruby","s3","google-cloud-storage"],"confidence":0.8,"fix_status":"available","needs_auth":"unknown","worst_case":"Server threads block until process restart, causing denial of service","analyst_note":"","how_to_check":"- Check the Rails version in the Gemfile.lock for `activestorage`\n- Confirm the app stores files on S3, an S3-compatible service or Google Cloud Storage\n- Confirm the app draws Active Storage's default routes","plain_action":"","product_name":"","needs_analyst":false,"not_affected_if":["non-streaming-storage","no-proxy-routes"],"who_is_affected":"Applications that store Active Storage files on a service that streams downloads in several requests, such as Amazon S3, an S3-compatible service or Google Cloud Storage, and that use Active Storage's default proxy routes. The proxy routes are drawn whether or not proxy mode is the default, so the exposure does not depend on that setting. Apps that serve files only through redirects or do not use these storage services can skip it.","user_interaction":"no","product_ecosystem":"","needs_special_setup":"unknown","severity_if_unknown":"unknown"},"cost_usd":0.000846,"input_tokens":5167,"output_tokens":659,"severity_before":"medium"},"analyst_status":null,"analyst_note":null,"search":"'-2026':344C '-772':28B '/rails/rails/commit/3c67a693fb21870ecb1222e3da59d5c491a62009.patch':328C '/rails/rails/commit/655b4442de136a3701334607f634d698bf9d5b82.patch':332C '404':105C,260C '4v2w':16A,21A '500':107C,262C '8.0':329C '8.1':325C 'actioncontrol':139C 'activ':5A,38B,78C,206C 'activestorag':26B,87C 'activestorage':24A,25A 'affect':176C 'alreadi':123C 'amazon':193C 'ant':343C 'anthrop':340C 'applic':174C,226C,303C 'avail':312C 'blob':90C 'block':60B,154C 'bodi':130C,297C 'buffer':141C,143C 'call':100C 'cannot':321C 'caus':71B 'chunk':116C 'client':293C 'close':146C,284C 'cloud':31B,202C 'commit':124C,256C,275C 'compat':198C 'condit':246C 'control':86C 'could':162C 'credit':333C 'cwe':27B 'default':209C,223C 'delet':229C 'denial':73B 'detail':247C 'dos':2A,172C 'download':65B,161C,187C,243C 'draw':205C 'drawn':215C 'error':11A,94C,111C,239C,250C,269C,305C 'except':300C 'exhaust':67B,163C 'f8f8':18A,23A 'fail':51B,64B,160C 'file':42B,82C,180C,228C 'first':115C 'fix':266C,309C 'fmpumytb':345C 'found':337C 'ghsa':15A,20A 'ghsa-4v2w-w6g6-f8f8':14A,19A 'github.com':327C,331C 'github.com/rails/rails/commit/3c67a693fb21870ecb1222e3da59d5c491a62009.patch':326C 'github.com/rails/rails/commit/655b4442de136a3701334607f634d698bf9d5b82.patch':330C 'googl':30B,201C 'google-cloud-storag':29B 'handl':92C,151C 'head':101C,126C 'impact':76C 'instead':280C 'issu':335C 'live':140C 'locat':316C 'mode':8A,220C 'never':145C 'normal':315C 'occur':112C 'origin':138C 'oss':341C 'packag':33B 'partway':240C 'patch':317C 'possibl':1A,168C 'process':157C 'produc':258C 'proxi':7A,45B,85C,212C,219C 'rail':34B 'rais':251C,270C,279C 're':278C 're-rais':277C 'reach':301C 'read':136C 'receiv':294C 'releas':289C,307C,310C 'repeat':63B,159C 'replac':127C 'report':306C 'request':153C,190C 'respons':54B,108C,121C,129C,254C,263C,273C,287C 'restart':62B,158C 'result':169C 'rout':46B,210C,213C 'rubi':35B 's3':36B,194C,197C 's3-compatible':196C 'scanner':342C 'send':89C,103C 'serv':80C,234C 'server':58B,68B,133C,149C,165C,283C 'servic':50B,75B,98C,183C,199C 'sever':189C 'start':56B 'still':135C,257C 'storag':6A,10A,32B,39B,49B,79C,97C,203C,207C,238C,249C,268C 'store':179C 'stream':13A,40B,88C,91C,185C,286C 'thread':59B,69B,150C,167C,291C 'trigger':244C 'truncat':296C 'upgrad':322C 'via':9A 'vulner':3A,173C 'w6g6':17A,22A 'whether':216C 'written':119C","nicknames":[],"mitigations":[],"who_affected":"Applications that store Active Storage files on a service that streams downloads in several requests, such as Amazon S3, an S3-compatible service or Google Cloud Storage, and that use Active Storage's default proxy routes. The proxy routes are drawn whether or not proxy mode is the default, so the exposure does not depend on that setting. Apps that serve files only through redirects or do not use these storage services can skip it.","tier":"C","verified":{},"analyst_revisit_at":null,"fix_status":"available","audience":"developers","plain_action":null,"pkeys":["activestorage"],"ptokens":["activestorage"],"labels":["activestorage","cwe772","googlecloudstorage","medium","package","rails","ruby","rubygems","s3"],"campaign_type":null,"search_a":"'4v2w':16A,21A 'activ':5A 'activestorage':24A,25A 'dos':2A 'error':11A 'f8f8':18A,23A 'ghsa':15A,20A 'ghsa-4v2w-w6g6-f8f8':14A,19A 'mode':8A 'possibl':1A 'proxi':7A 'storag':6A,10A 'stream':13A 'via':9A 'vulner':3A 'w6g6':17A,22A","search_b":"'-772':28B 'activ':38B 'activestorag':26B 'block':60B 'caus':71B 'cloud':31B 'cwe':27B 'denial':73B 'download':65B 'exhaust':67B 'fail':51B,64B 'file':42B 'googl':30B 'google-cloud-storag':29B 'packag':33B 'proxi':45B 'rail':34B 'repeat':63B 'respons':54B 'restart':62B 'rout':46B 'rubi':35B 's3':36B 'server':58B,68B 'servic':50B,75B 'start':56B 'storag':32B,39B,49B 'stream':40B 'thread':59B,69B","search_c":"'-2026':344C '/rails/rails/commit/3c67a693fb21870ecb1222e3da59d5c491a62009.patch':328C '/rails/rails/commit/655b4442de136a3701334607f634d698bf9d5b82.patch':332C '404':105C,260C '500':107C,262C '8.0':329C '8.1':325C 'actioncontrol':139C 'activ':78C,206C 'activestorag':87C 'affect':176C 'alreadi':123C 'amazon':193C 'ant':343C 'anthrop':340C 'applic':174C,226C,303C 'avail':312C 'blob':90C 'block':154C 'bodi':130C,297C 'buffer':141C,143C 'call':100C 'cannot':321C 'chunk':116C 'client':293C 'close':146C,284C 'cloud':202C 'commit':124C,256C,275C 'compat':198C 'condit':246C 'control':86C 'could':162C 'credit':333C 'default':209C,223C 'delet':229C 'detail':247C 'dos':172C 'download':161C,187C,243C 'draw':205C 'drawn':215C 'error':94C,111C,239C,250C,269C,305C 'except':300C 'exhaust':163C 'fail':160C 'file':82C,180C,228C 'first':115C 'fix':266C,309C 'fmpumytb':345C 'found':337C 'github.com':327C,331C 'github.com/rails/rails/commit/3c67a693fb21870ecb1222e3da59d5c491a62009.patch':326C 'github.com/rails/rails/commit/655b4442de136a3701334607f634d698bf9d5b82.patch':330C 'googl':201C 'handl':92C,151C 'head':101C,126C 'impact':76C 'instead':280C 'issu':335C 'live':140C 'locat':316C 'mode':220C 'never':145C 'normal':315C 'occur':112C 'origin':138C 'oss':341C 'partway':240C 'patch':317C 'possibl':168C 'process':157C 'produc':258C 'proxi':85C,212C,219C 'rais':251C,270C,279C 're':278C 're-rais':277C 'reach':301C 'read':136C 'receiv':294C 'releas':289C,307C,310C 'repeat':159C 'replac':127C 'report':306C 'request':153C,190C 'respons':108C,121C,129C,254C,263C,273C,287C 'restart':158C 'result':169C 'rout':210C,213C 's3':194C,197C 's3-compatible':196C 'scanner':342C 'send':89C,103C 'serv':80C,234C 'server':133C,149C,165C,283C 'servic':98C,183C,199C 'sever':189C 'still':135C,257C 'storag':79C,97C,203C,207C,238C,249C,268C 'store':179C 'stream':88C,91C,185C,286C 'thread':150C,167C,291C 'trigger':244C 'truncat':296C 'upgrad':322C 'vulner':173C 'whether':216C 'written':119C","cause_entry":null,"cause_path":null,"disclosures_checked_at":null,"first_public_at":"2026-11-04T03:02:00+00:00","kev":null,"cvss_vector":null,"cvss_by":null,"poc_count":0,"sources":[{"source":"ghsa-repo","external_id":"GHSA-4v2w-w6g6-f8f8","url":"https://github.com/rails/rails/security/advisories/GHSA-4v2w-w6g6-f8f8","severity":"medium","published_at":"2026-11-04T03:02:00+00:00","modified_at":"2026-11-04T03:02:00+00:00","first_seen_at":"2026-11-09T22:53:29+00:00","fetched_at":"2026-11-09T22:53:29+00:00","note":null}],"documents":[{"id":110677,"url":"https://github.com/rails/rails/security/advisories/GHSA-4v2w-w6g6-f8f8","title":"Maintainer's advisory: github.com","kind":"vendor","source":"ghsa-repo","publisher":"vendor","text":null,"published_at":null,"relation":"advisory","confidence":null,"note":"Maintainer's advisory: github.com"}],"disclosures":[],"exploit_sources":[],"notice":"Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai"}