Skip to main content
cd ../config-traps
risk/register/s3-default-bucket-encryption-skips-existing-objects.html
AWS Storage Securitymedium severityAmazon Web Services

S3 Default Bucket Encryption Skips Every Object Uploaded Before It Was Enabled

Severity
medium
Reviewed
14 Aug 2026
Remediation
~20 minutes
Overview

Turning on Amazon S3 default bucket encryption looks like a bucket-wide fix, but it only governs new writes. Objects already stored before the change remains untouched, and audits that trust the flag alone miss it.

Operational summary

At a glance

Symptom
Enabling S3 Bucket Default Encryption on an existing bucket does not encrypt the objects that were already stored there before the setting was applied…
Likely cause
The root cause is that S3 bucket-level default encryption is a write-time policy, not a retroactive transformation: it determines what encryption AWS applies to…
Impact
The operational consequence is a false sense of assurance: a security review that checks only the bucket's default-encryption configuration will report the bucket as encrypted, while any object…
Verification signal
Validation confirms that every previously unencrypted object now reports the intended encryption algorithm on inspection, not merely that the bucket-level default remains enabled.Re-run aws s3api head-object against every…
Safe correction
The correction is to explicitly rewrite each identified unencrypted object using a copy-in-place operation that applies the desired encryption setting, because the bucket-level default only governs future writes…
Rollback or recovery
Rollback is only viable when S3 Versioning was confirmed enabled before the correction ran, because a copy-in-place under versioning creates a new object version rather than mutating the…

Symptom

Enabling S3 Bucket Default Encryption on an existing bucket does not encrypt the objects that were already stored there before the setting was applied, so a subset of stored data remains in its original, unencrypted state even though every bucket-level dashboard reports the encryption control as “Enabled”.

A typical trigger is a migrated logging or archive bucket: a platform team turns on server-side encryption (SSE-S3 or SSE-KMS) as part of a security remediation sprint, closes the associated ticket, and later discovers during an access-control or breach-readiness review that a meaningful share of the objects in that bucket still return no ServerSideEncryption header when inspected individually.

False Assumption

The team assumed that switching on default encryption is a bucket-wide, backward-applying control: that flipping the toggle brings every object currently stored in the bucket into an encrypted state, not only the objects written after the setting was applied.

That assumption is reinforced by the console language itself. The setting is presented as a property of the bucket (“Default encryption: Enabled”) rather than as a rule that only governs future PutObject calls. Change-management sign-off in this scenario reviewed the configuration flag as evidence of completion, because verifying encryption status for every object in a large bucket individually is neither the default audit method nor something most teams build into a standard change review.

Root Cause

The root cause is that S3 bucket-level default encryption is a write-time policy, not a retroactive transformation: it determines what encryption AWS applies to an object at the moment it is written, and it has no effect on objects that already exist in the bucket at the time the setting is changed.

This is consistent with the broader operational principle set out in the AWS Well-Architected Security Pillar, which frames encryption and other protective controls as practices that must be actively verified rather than assumed from a single configuration state. The Security Pillar documents design principles and operational practices for protecting AWS workloads, and does not, on its own, confirm the specific object-level retroactivity behaviour described here. That specific mechanism-level detail is treated in this article as a widely documented but not independently re-verified claim, and it is flagged below for human confirmation against current AWS S3 documentation before this article is relied upon for a compliance attestation.

Impact

The operational consequence is a false sense of assurance: a security review that checks only the bucket’s default-encryption configuration will report the bucket as encrypted, while any object written before that setting was enabled remains exactly as it was, unprotected by the control the review believes is in effect.

For regulated workloads, this gap can invalidate an encryption-at-rest attestation for a specific date range, complicate breach-notification scoping if the bucket is later implicated in an incident, and propagate a false assurance into downstream audits or customer-facing security statements that cite the bucket-level flag as evidence.

Diagnosis

Diagnosis starts by separating the bucket-level configuration from the per-object reality, using read-only checks before any object is touched.

  1. Confirm the current default-encryption configuration with aws s3api get-bucket-encryption.
  2. Confirm whether S3 Versioning is enabled with aws s3api get-bucket-versioning; this determines whether any later correction can be rolled back.
  3. Take a bounded sample of object keys with aws s3api list-objects-v2, prioritising objects known or suspected to predate the default-encryption change.
  4. Inspect each sampled key individually with aws s3api head-object and check for the presence of the ServerSideEncryption field.
aws s3api get-bucket-encryption --bucket example-logging-bucket
aws s3api get-bucket-versioning --bucket example-logging-bucket
aws s3api list-objects-v2 --bucket example-logging-bucket --max-items 50 --query 'Contents[].Key'
aws s3api head-object --bucket example-logging-bucket --key logs/2024/01/01/access.log

An object with no ServerSideEncryption field in its head-object output was written before the current default encryption setting took effect, or was uploaded with an explicit request to bypass it, and requires the correction below.

Correction

The correction is to explicitly rewrite each identified unencrypted object using a copy-in-place operation that applies the desired encryption setting, because the bucket-level default only governs future writes and cannot be relied upon to change existing ciphertext.

aws s3 cp s3://example-logging-bucket/logs/2024/01/01/access.log 
  s3://example-logging-bucket/logs/2024/01/01/access.log 
  --sse AES256 --metadata-directive COPY

This must only be run once aws s3api get-bucket-versioning has confirmed Status: Enabled. For buckets holding more than a few hundred affected objects, a per-object CLI loop does not scale reliably against request-rate and execution-time limits; scope the work instead to a manifest-driven batch job covering only the keys confirmed unencrypted in the diagnosis step, and re-verify a sample afterwards rather than assuming the job succeeded uniformly.

Validation

Validation confirms that every previously unencrypted object now reports the intended encryption algorithm on inspection, not merely that the bucket-level default remains enabled.

  • Re-run aws s3api head-object against every corrected key and confirm the ServerSideEncryption field now matches the intended algorithm.
  • Re-run aws s3api get-bucket-encryption to confirm the bucket-level configuration is unchanged by the correction itself.
  • If S3 Inventory or an equivalent reporting mechanism is configured, confirm the corrected keys no longer appear in an unencrypted-object report.

Rollback

Rollback is only viable when S3 Versioning was confirmed enabled before the correction ran, because a copy-in-place under versioning creates a new object version rather than mutating the object irreversibly.

  1. Identify the prior version ID with aws s3api list-object-versions --bucket example-logging-bucket --prefix logs/2024/01/01/access.log.
  2. Restore the prior version with a versioned copy-back operation if the correction caused an unexpected application or integrity failure.
  3. If versioning was not enabled before the correction ran, treat the prior object content as unrecoverable, record this as a permanent limitation in the change record, and escalate to the data owner rather than attempting an unsupported restore.

Prevention

Preventing recurrence means treating the default-encryption toggle as a forward-only control in every future change-management review, rather than as proof that existing data is protected.

  • Enable default encryption at bucket creation time wherever possible, so there is no window in which unencrypted objects can be written.
  • Add a bucket policy condition that denies s3:PutObject requests lacking the expected x-amz-server-side-encryption header, so future uploads cannot silently bypass the default.
  • Enable S3 Versioning before enabling default encryption on any bucket that may later need object-level correction, so remediation work remains reversible.
  • Use S3 Inventory, or an equivalent scheduled report, to track per-object encryption status as an ongoing signal, and treat the bucket-level configuration flag as only one input into a compliance attestation, never the sole evidence.
03

Apply the safer control

Before you change production

Confirm the affected scope, export the current configuration, and test the replacement control in a non-production environment first.

Fix commands and configuration

ServerSideEncryption
PutObject
aws s3api get-bucket-encryption
04

Verify, roll back or escalate

Verify

Validation confirms that every previously unencrypted object now reports the intended encryption algorithm on inspection, not merely that the bucket-level default remains enabled.Re-run aws s3api head-object against every corrected key and confirm the ServerSideEncryption field now matches the intended algorithm.Re-run…

Rollback

Rollback is only viable when S3 Versioning was confirmed enabled before the correction ran, because a copy-in-place under versioning creates a new object version rather than mutating the object irreversibly.Identify the prior version ID with aws s3api list-object-versions --bucket example-logging-bucket…

Escalate

Escalate when the blast radius is uncertain, the control cannot be tested safely, or remediation requires an outage or security exception.

After remediation

Further reading stays below the corrective workflow and is selected by platform, category and shared technical keywords.

Discover more

Connected KBY resources