---
id: "GHSA-3w93-6hmw-whh4"
page: "https://infrastack.ai/live/GHSA-3w93-6hmw-whh4"
kind: "vulnerability"
aliases: ["GHSA-3w93-6hmw-whh4"]
title: "Unsigned Content-Type in Active Storage GCS direct uploads with cache_control"
severity: "medium"
cvss: 4.7
epss: null
exploited: false
status: "open"
category: "package"
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.5.2", "ecosystem": "rubygems"}]
ecosystems: ["rubygems"]
tags: ["activestorage", "cwe-345", "gcs", "package", "rails", "ruby"]
not_affected_if: ["no-cache-control-option", "no-direct-uploads", "non-gcs-storage"]
published_at: "2026-11-04T03:01:59+00:00"
first_seen_at: "2026-11-09T22:53:29+00:00"
updated_at: "2026-11-09T22:57:10+00:00"
sources: [{"source": "ghsa-repo", "url": "https://github.com/rails/rails/security/advisories/GHSA-3w93-6hmw-whh4", "first_seen_at": "2026-11-09T22:53:29+00:00"}]
exploit_sources: []
---

# Unsigned Content-Type in Active Storage GCS direct uploads with cache_control

Link for people: https://infrastack.ai/live/GHSA-3w93-6hmw-whh4 (this .md is for agents)

When an Active Storage GCS service has the cache_control option set, direct-upload URLs are signed with V4, which does not cover Content-Type or Content-MD5. A client can upload an object with a chosen content type, such as HTML, that GCS may then serve from the bucket path on storage.googleapis.com.

_Summary, check and fix written by a model from the sources; labelled as such._

## Affected

- rubygems:activestorage affected >= 8.1, < 8.1.4.1 fixed 8.1.4.1
- rubygems:activestorage affected < 8.0.5.2 fixed 8.0.5.2

## How to check

- Check the Rails version in `Gemfile.lock` for `activestorage`, against the affected ranges
- Look in `config/storage.yml` for a GCS service that sets `cache_control`
- Check whether that service accepts direct uploads from clients

## Fix

- `activestorage` 8.1.x: move to `8.1.4.1`
- `activestorage` 8.0.x: move to `8.0.5.2`
- Workaround: remove the `cache_control` option from the GCS service configuration

## Timeline

- 2026-11-09T22:53:29+00:00 ghsa-repo https://github.com/rails/rails/security/advisories/GHSA-3w93-6hmw-whh4

## Documents

- [advisory] Maintainer's advisory: github.com https://github.com/rails/rails/security/advisories/GHSA-3w93-6hmw-whh4

## From the sources

### Impact
When a GCS service is configured with the `cache_control` option, `ActiveStorage::Service::GCSService#url_for_direct_upload` signs direct-upload URLs with V4, and the V4 signature covers only the `Cache-Control` and `Host` headers. A direct-upload client can therefore send a `Content-Type` of its choosing, and can omit the declared `Content-MD5`, without invalidating the URL. GCS stores the supplied content type as object metadata, which takes precedence over the `response-content-type` that Active Storage sets on download URLs, so an uploaded object could be served as inline HTML under the application's bucket path on `storage.googleapis.com`. Script in such an object runs on the storage origin rather than the application's, but could register a Service Worker scoped to the bucket path and read or replace a victim's later responses for signed URLs in that bucket.

Applications that use the GCS service with `cache_control` configured and accept direct uploads are affected. GCS services without `cache_control` sign with V2 and are not affected.

### Details
The fixed releases sign every GCS direct-upload URL with V2, which binds an empty `Content-Type` and the declared `Content-MD5`. The configured `Cache-Control` is still returned by `headers_for_direct_upload` and sent by the client, but it is no longer part of the signature, and direct-upload URLs for these services are no longer limited to V4's seven-day maximum expiry. See the Active Storage CHANGELOG.

### Workarounds
Removing the `cache_control` option from the GCS service configuration makes Active Storage sign direct uploads with V2.

### Releases
The fixed releases are available at the normal locations.

Patches for those who cannot upgrade at once:
- 8.1: https://github.com/rails/rails/commit/8d93f6a872e9550a91bf0e4fce50083a235ef3b1.patch
- 8.0: https://github.com/rails/rails/commit/ddc08ba61a8001e7402864c62e466cf732fc7614.patch

### Credit
This issue was responsibly reported by HackerOne researcher [thepo1es](https://hackerone.com/thepo1es).

---

_Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai_
