Thesis: Cross-origin fetch cannot read Content-Disposition (or a custom X-Filename header) unless the API’s CORS configuration exposes them. If JavaScript cannot see the header, your Save-As fallback will sanitize the artifact title — and titles rarely include .tf or .md.
The failure mode
Authenticated downloads often look like this:
- SPA calls GET /artifacts/{id}/download with a Bearer token.
- API returns binary bytes plus Content-Disposition: attachment; filename="thing.tf".
- Client builds a Blob and calls a.download = filename.
Step 3 only works if step 2’s headers are visible to script. Under the Fetch CORS rules, most response headers are opaque unless listed in Access-Control-Expose-Headers. Lambda can emit the right headers and still lose: when API Gateway HTTP API manages CORS, its expose list wins.
Fix the gateway, not only the Lambda
On API Gateway HTTP APIs, set CORS expose_headers to include at least:
- Content-Disposition
- Content-Type
- Any custom header you invent for the basename (for example X-Filename)
Confirm with a real browser session, not only curl. Curl always sees headers; JavaScript does not.
Defense in depth: basename on the list DTO
Even with expose-headers fixed, keep a safe download basename on the list payload — the leaf name only ( codepipeline_portal.tf), not the full object key. The UI can prefer:
- Header / X-Filename
- DTO filename
- Sanitized title (last resort)
That avoids re-introducing path disclosure while surviving the next CORS regression. Do not put storage prefixes or assessor notes on the public list DTO.
Titles vs files
Humans want titles like “CI pipeline and release evidence.” Filesystems want codepipeline_portal.tf. Keep both: display the title, download the basename. When they collide in the UI fallback, you get underscores and no extension — exactly the bug users report as “weird filename.”
Checklist
- Expose download-related headers on the HTTP API CORS block.
- Parse filename and filename* from Content-Disposition; prefer an explicit X-Filename if you set one.
- Include a leaf filename on the list DTO as fallback.
- Never use the marketing title as the only Save-As name for binary artifacts.
Next: prefix keys, identical 404s, and per-tenant KMS.
Engineering commentary only — not audit, legal, or certification advice.