Zum Hauptinhalt springen
Echtzeit-Radar & Feeds
Alle RSS Feeds ➔
👥 Community & Social
••••••••••••••••••••
Intelligence View
⚡ tsecurity.de Intelligence

🕵️‍♂️ The Case of the Missing S3 Metadata: A CORS Deep Dive

When you upload a file to S3 with custom metadata (like fileName or uploadedAt), everything looks correct in the AWS Console. But when you try to read that metadata from your frontend using HeadObjectCommand, the data clearly exists on the…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!

When you upload a file to S3 with custom metadata (like fileName or uploadedAt), everything looks correct in the AWS Console. But when you try to read that metadata from your frontend using HeadObjectCommand, the data clearly exists on the cloud, yet the AWS SDK response returns empty Metadata object.



There's a resolved GitHub issue on one of the JavaScript AWS packages.



This is not an bug, the cause isn’t in the AWS SDK or your upload logic. It comes from the browser, and specifically how it handles cross-origin requests.



The rest of this article breaks down where this behavior comes from and how to fix it.







If you read my earlier article, “Stop Uploading Files to S3 the Wrong Way”, you saw a complete example of how to upload and download files efficiently using the AWS SDK with a client/server flow.



This article builds directly on top of that and acts as a follow-up for developers searching for “client-side S3 metadata not showing” issues.










Table of Contents




  • This is Part 2 in a small S3 series

  • Client and Server behave differently

  • Why no Metadata on the Client

  • How to Fix It with S3 CORS Rules









This is Part 2 in a small S3 series



In the first part, the focus was sending and retrieving files. Here, we look at reading custom metadata from a cloud S3 provider in the browser.



You don’t need to read Part 1 to follow this article, but both posts fit together if you’re building a file upload pipeline end-to-end.






Client and Server behave differently



The issue only shows up in certain execution environments, so it helps to look at how the same code behaves in your backend (when it runs on the server) versus in the browser.






Server-side (✅ works as expected)



When HeadObjectCommand runs in a nodejs backend environment - for example, a Next.js API route - it returns the full metadata without any issues. Server-to-server requests aren’t limited by browser security rules, so all response headers are available.




// src/app/api/s3/private/meta/route.ts
import { s3Service } from '../../_lib';

export const GET = async (req: NextRequest) => {
const documentKey = request.nextUrl.searchParams.get('key') as string;
const metadata = await s3Service.getMetadata(documentKey);
return NextResponse.json(metadata);
};









Client-side (❌ metadata comes back empty)



The problem appears when the same request is made from browser JavaScript.

The call succeeds, but the Metadata object in the AWS SDK response is empty.




// src/app/api/s3/_lib/s3Service.ts
export const getFileMetadata = async (id: string) => {
const response = await s3.send(
new HeadObjectCommand({
Bucket: bucketName,
Key: id,
})
);

return response.Metadata; // {} without proper CORS
};

// src/components/File.tsx
useEffect(() => {
async function setFilename() {
const fileMetadata = await getFileMetadata(file.documentId);
return {
...contract,
// fileMetadata is empty, so this becomes undefined
filename: fileMetadata?.filename,
};
});
}
setFilename();
}, [file]);






The request itself isn’t failing. S3 returns the metadata correctly.

But because the code runs in the browser, certain response headers - including S3’s custom metadata headers - are not exposed to JavaScript by default.



The next section explains why this happens.





Why no Metadata on the Client



Two fundamental security mechanisms are involved here: the Same-Origin Policy (SOP) and Cross-Origin Resource Sharing (CORS).



S3 CORS expose headers, custom metadata missing browser, or AWS CORS not working.



1. Same-Origin Policy



Browsers enforce a rule that pages can only freely access resources from the same “origin,” defined by scheme, host, and port.

Your frontend (https://your-app.com) and S3 (https://your-bucket.s3.amazonaws.com) are different origins, so the browser restricts what your code can access.



2. CORS as the exception



CORS is a system that allows a server to relax these restrictions.

If you configure S3 with an AllowedOrigin matching your frontend, the browser is permitted to make the request.



However, this only covers whether the request can happen - not what the browser exposes back to your JavaScript.



3. Access-Control-Expose-Headers



Even with CORS enabled, the browser only exposes a small set of safe default headers to the client.

S3’s custom metadata headers (x-amz-meta-*) are not part of that list.



This means:




  • S3 sends the metadata correctly.

  • The browser receives it.

  • But the browser filters it out or hides it before the AWS SDK gets the response.



The SDK sees no metadata headers and correctly (from its perspective) returns an empty Metadata object. Unless your S3 bucket explicitly exposes the metadata headers through CORS, your client code will always see Metadata: {}.





How to Fix It with S3 CORS Rules



How do I fix S3 CORS so metadata shows up in HeadObject?



To make your metadata visible in the browser, you need to add your metadata fields to Access-Control-Expose-Headers in your S3 bucket’s CORS config so the browser is allowed to expose the headers you care about.



Add them to its HEAD request responses. This is done by updating the CORS configuration on your S3 bucket, as detailed in the official Amazon S3 User Guide on Managing CORS.



A working XML example looks like this:




<!-- S3 Bucket CORS Configuration (XML) -->
<CORSConfiguration>
<CORSRule>
<AllowedOrigin>https://your-app.com</AllowedOrigin>
<AllowedMethods>GET</AllowedMethod>
<AllowedMethods>HEAD</AllowedMethod>
<AllowedHeaders>*</AllowedHeader>
<ExposeHeaders>x-amz-meta-filename</ExposeHeader>
<ExposeHeaders>x-amz-meta-uploaded-by</ExposeHeader>
<!-- Add an <ExposeHeader> for each custom metadata key you use -->
</CORSRule>
</CORSConfiguration>






JSON Configuration Example:




// S3 Bucket CORS Configuration (JSON)
{
"CORSRules": [
{
"AllowedOrigins": ["<https://your-app.com>"],
"AllowedMethods": ["GET", "HEAD"],
"AllowedHeaders": ["*"],
"ExposeHeaders": ["x-amz-meta-filename", "x-amz-meta-uploadedat"]
}
]
}






This enables client-side S3 HeadObject to return the full metadata object.



A few important details:




  • Expose only the headers you need.
    The browser will ignore everything else.

  • HEAD and GET both matter.
    If you’re calling HeadObjectCommand from the client, the HEAD method must be included or the request may fail depending on your setup.

  • Wildcard AllowedHeaders is fine here. It simply allows the browser to send custom headers, not expose them.



After this configuration is applied, the browser will no longer filter out the metadata, and your AWS SDK call will return the full Metadata object instead of {}.



👉 Missed Part 1?

Read the full upload/download pipeline here: Stop Uploading Files to S3 the Wrong Way

1. Sofort-Triage & Abwehrmaßnahmen

SOC Incident Playbook: Remote Code Execution (RCE) Defense
Syntax validiert (0 Fehler)
title: Detect Exploitation - 🕵️‍♂️ The Case of the Missing S3 Metadata: A CORS Deep Dive
id: 4f895224-e762-4c9c-b9f7-af34760d6003
status: experimental
description: Automatisch generierte SIEM-Erkennungsregel basierend auf CTI Intelligence
references:
  - https://tsecurity.de/
author: iShareStuff CTI Automated Detection Engine
date: 2026-09-25
logsource:
  category: network_connection
  product: any
detection:
  selection:
      CommandLine|contains:
        - 'exploit'
  condition: selection
falsepositives:
  - Legitime administrative Zugriffe oder Penetrationstests
level: high
tags:
  - attack.initial_access
Syntax validiert (0 Fehler)
rule CTI_Threat_Indicator {
    meta:
        author = "iShareStuff CTI Automated Detection Engine"
        date = "2026-09-25"
        description = "YARA Signature for "
    strings:
        $str = "🕵️‍♂️ The Case of the Missing " ascii wide
    condition:
        any of them
}
Syntax validiert (0 Fehler)
index=security sourcetype IN ("cisco:asa", "pan:traffic", "zeek_conn", "suricata", "WinEventLog:Security")
("The Case of the Missing S3 Metadata A CO")
| stats count earliest(_time) as first_seen latest(_time) as last_seen by src_ip, dest_ip, dest_host, signature
| eval first_seen=strftime(first_seen, "%Y-%m-%d %H:%M:%S"), last_seen=strftime(last_seen, "%Y-%m-%d %H:%M:%S")
| sort - count
Syntax validiert (0 Fehler)
message: "*The Case of the Missing S3 Metadata A CO*"
Syntax validiert (0 Fehler)
CommonSecurityLog
| where Message has "The Case of the Missing S3 Metadata A CO"
| summarize EventCount = count(), FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated) by SourceIP, DestinationIP, DestinationPort, Activity
| extend DetectionRule = "iShareStuff-CTI-Compiled"
| sort by EventCount desc

2. Cyber Threat Intelligence & Forensik

🎯
MITRE ATT&CK Matrix Navigator 14 Taktiken
Reconnaissance
-
Resource Development
-
Initial Access
Execution
Persistence
-
Privilege Escalation
Defense Evasion
Credential Access
-
Discovery
-
Lateral Movement
-
Collection
-
Command and Control
Exfiltration
-
Impact
tsecurity.de Cognitive Threat RAG
Fokus-Vektor:

Kognitive Analyse für identifizierte Bedrohung: Erhöhte Bedrohungslage im Bereich 🕵️‍♂️ The Case of the Missing S3 Metadat.... Basierend auf 368k Vektor-Korrelationen werden sofortige Isolationsmaßnahmen für betroffene Endpunkte empfohlen.

🛡️ Angriffsfläche & Exposure

Netzwerk/Remote-Zugriff ohne Vorauthentifizierung möglich.

⚡ Empfohlene Sofortmaßnahmen
  • 1. Perimeter-Inspektion: Relevante Portfreigaben und exponierte Endpunkte unverzüglich scannen.
  • 2. Patch-Applikation: Hersteller-Hotfix einspielen oder betroffene Daemons in isolierte DMZ-Segmente überführen.
  • 3. Telemetrie & EDR-Alerts: Prozessaufrufe und Child-Processes auf anomale Shell-Spawns überwachen.
🔗 Semantisch verwandte Zero-Days MariaDB 11.7 VEC
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten 🕵️‍♂️ The Case of the Missing S3 Metadata: A CORS Deep Dive

Thematisch verwandte Begriffe: Case, Missing, Metadata, CORS · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-87722 | Uncontrolled Resource Consumption (CWE-400 / CWE-1333) in regex search q…
Advisory →
tsecurity.de Icon
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel • Rechts: nächster Artikel • unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel TTP ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...
↗ Original-Quelle