S3 Signature Requirements
On 23 August 2026 we applied a security update to DanubeData Object Storage. It tightened how request signatures are checked, and it can cause uploads to fail while downloads keep working.
A temporary compatibility setting is in place, so uploads work normally until 30 August 2026. If one of your clients is affected, correct it before that date.
The rule
Our S3 endpoint enforces the standard AWS Signature Version 4 rule. Three groups of headers must be covered by your request signature whenever they are present:
- the
Hostheader - every
x-amz-*header - the
Content-Typeheader
Most SDKs already do this and need no change. Two common cases do not, and both are covered below.
Why the update was applied
The update fixes CVE-2026-54330, rated Important, along with three other vulnerabilities disclosed on 19 August 2026. Before the fix, a request could carry headers the signature did not cover, which meant anyone holding a presigned upload URL could attach extra headers and obtain more read and write access than whoever issued that URL intended. Because that directly exposes customer data, we applied the update within days of disclosure rather than waiting for a quieter maintenance window.
Independent references: Red Hat and CERT-FR advisory CERTFR-2026-AVI-1057.
How to recognise an affected request
A rejected request returns:
- HTTP status
403 - Error code
AccessDenied - An empty
<Message>element
The request is refused before any permission check, which is why the symptom is confusing:
- uploads fail, but downloads and listings still succeed
- access keys marked Full are still rejected
- the bucket policy is correct and unchanged
If you see that combination, this rule is the cause. It is not a permissions problem, and rotating your keys will not help.
A request that fails the signature check itself returns SignatureDoesNotMatch instead. That is a different problem, usually a wrong secret key, a clock difference of more than 15 minutes, or a mismatch between the header you signed and the header you sent.
Case 1 — presigned upload URLs
If your presigned URL signs only host but the uploading client sends a Content-Type header, the upload is rejected. Browsers always set Content-Type when uploading a file, so this affects most browser upload flows.
You can see what a URL covers by looking at its X-Amz-SignedHeaders parameter.
Preferred fix: sign the content type
Pass the content type when generating the URL, then send exactly that header. The signed URL will then show X-Amz-SignedHeaders=content-type;host.
AWS SDK for JavaScript v3
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3'
import { getSignedUrl } from '@aws-sdk/s3-request-presigner'
const url = await getSignedUrl(
s3,
new PutObjectCommand({ Bucket: bucket, Key: key, ContentType: file.type }),
{ expiresIn: 600 },
)
await fetch(url, {
method: 'PUT',
headers: { 'Content-Type': file.type },
body: file,
})
boto3 (Python)
url = s3.generate_presigned_url(
'put_object',
Params={'Bucket': bucket, 'Key': key, 'ContentType': 'image/jpeg'},
ExpiresIn=600,
)
The header you send must match the one you signed exactly. If they differ you get SignatureDoesNotMatch.
This is the recommended option because the stored object keeps its correct content type, which matters when the bucket serves files publicly.
Alternative fix: send no content type
Do not send a Content-Type header at all.
await fetch(url, { method: 'PUT', body: await file.arrayBuffer() })
curl -T photo.jpg "<presigned-url>"
This works immediately, but objects are then stored as binary/octet-stream.
Quick check
Take a fresh presigned URL and run:
curl -T photo.jpg "<presigned-url>"
A 200 proves your keys and bucket are fine and that no key rotation is needed.
Case 2 — the AWS SDK for PHP
aws-sdk-php never covers Content-Type in its signature, so any upload it makes that carries that header is rejected. The SDK cannot be configured to sign it without a custom signer class.
If you control the code, the options are:
- upload without setting
ContentType, or - subclass the SDK's
SignatureV4to removecontent-typefrom its header blacklist, or - upload through your own backend instead of a presigned URL
If you would like the signer subclass we use ourselves, open a ticket and we will share it.
This also affects appliances that bundle the SDK. The most common is Synology Hyper Backup — see Synology Hyper Backup for a complete walkthrough.
Signature Version 2
Signature Version 2 covers Content-Type as part of the signature by design, so it is unaffected by this change and remains supported on our endpoints. It is the recommended workaround for appliances whose S3 client cannot be updated.
Signature Version 4 is still preferred wherever your client signs correctly, as it is the stronger scheme.
Clients confirmed working
No change is needed for the AWS SDK for JavaScript, boto3 and other Python clients, the AWS SDK for Go, the AWS SDK for .NET, rclone, MinIO clients over HTTPS, or s3cmd.
Endpoints
| Endpoint | Notes |
|---|---|
https://s3.danubedata.ro | Primary endpoint |
https://new-s3.danubedata.ro | Also available |
Both endpoints accept path-style (https://s3.danubedata.ro/your-bucket) and virtual-hosted-style (https://your-bucket.s3.danubedata.ro) addressing, and both Signature Version 4 and Signature Version 2.
Need help?
Open a ticket from your dashboard. We can look at your bucket's request logs and tell you whether anything you run will break on 30 August 2026, and help you adjust a client or a backup appliance before then.