Skip to content

fix(media): restore AVIF to the default upload allowlist - #2683

Merged
ascorbic merged 1 commit into
emdash-cms:mainfrom
hossein-webdev:fix/avif-media-uploads
Aug 27, 2026
Merged

fix(media): restore AVIF to the default upload allowlist#2683
ascorbic merged 1 commit into
emdash-cms:mainfrom
hossein-webdev:fix/avif-media-uploads

Conversation

@hossein-webdev

Copy link
Copy Markdown
Contributor

What does this PR do?

AVIF uploads fail with File type not allowed. image/avif is missing from the default media allowlist, so a .avif file is rejected before it ever reaches storage.

Root cause. The regression came from #2250, not from the commit named in the issue. #2250 replaced the bare "image/" prefix match in GLOBAL_UPLOAD_ALLOWLIST with an explicit enumeration of safe raster types so that image/svg+xml would stop being accepted by default — a deliberate and correct security fix, since there is no upload-time content validation for SVG. image/avif was covered by the old prefix match but was not carried into the new enumeration. ffaadc4 (#2553) later aligned the admin accept attribute and the docs table with that shortened list, which is why the issue points there.

The rest of the codebase already treats AVIF as a supported inline raster type — SAFE_INLINE_TYPES in routes/api/media/file/[...key].ts and SAFE_INLINE_IMAGE_TYPES in media/image-endpoint.ts both list image/avif. EmDash would serve an AVIF inline but refuse to accept one; the upload gate was the only place that disagreed.

The change. image/avif is restored in the three places a .avif file is turned away:

  • GLOBAL_UPLOAD_ALLOWLIST — the server-side gate that produces the error
  • EXTENSION_TO_MIME in core and admin — so .avif works as extension shorthand in a field's allowedMimeTypes
  • The admin upload dialog's accept filter and thumbnail preview set, plus the built-in "Images" preset in the allowed-types editor

SVG stays excluded from the default allowlist — #2250's protection is untouched.

Closes #2602

Type of change

  • Bug fix
  • Feature (requires maintainer-approved Discussion)
  • Refactor (no behavior change)
  • Translation
  • Documentation
  • Performance improvement
  • Tests
  • Chore (dependencies, CI, tooling)

Checklist

  • I have read CONTRIBUTING.md
  • pnpm typecheck passes
  • pnpm lint passes
  • pnpm test passes (or targeted tests for my change)
  • pnpm format has been run
  • I have added/updated tests for my changes (if applicable)
  • User-visible strings in the admin UI are wrapped for translation (if applicable) — n/a, no new user-visible strings; the admin changes are MIME constants. No messages.po changes are included.
  • I have added and reviewed the user-facing changeset (patch for emdash and @emdash-cms/admin)
  • New features link to an approved Discussion — n/a, bug fix

AI-generated code disclosure

  • This PR includes AI-generated code — model/tool: Claude Opus 5 (Claude Code)

Screenshots / test output

Both new assertions were written first and observed failing against the unfixed allowlist:

FAIL  tests/unit/media/media-allowlist.test.ts > GLOBAL_UPLOAD_ALLOWLIST > allows image/avif, which the media routes already serve inline
AssertionError: expected false to be true // Object.is equality

FAIL  tests/unit/media/mime.test.ts > expandExtensionShorthand > expands known dot-extensions
AssertionError: expected null to be 'image/avif' // Object.is equality

After the fix, the full core media suite passes:

Test Files  15 passed (15)
     Tests  150 passed (150)

pnpm lint (oxlint --type-aware --deny-warnings) exits clean, and pnpm typecheck passes.

One note on the full pnpm --filter emdash test run: 18 tests across 10 files fail in my local Windows environment (path-separator assertions, pnpm-symlink resolution, system tar, file-based SQLite). I verified these fail identically on an unmodified main checkout — same 18 failures, same 10 files — so they are pre-existing and unrelated to this change. Every media test passes.

emdash-cms#2250 replaced the bare "image/" prefix match in GLOBAL_UPLOAD_ALLOWLIST with an
explicit enumeration of safe raster types, so that image/svg+xml would stop being
accepted by default. image/avif was covered by the old prefix match but was not
carried into the enumeration, so AVIF uploads started failing with "File type not
allowed".

Both media serving paths already treat image/avif as safe to render inline, so
the upload gate was the only place that disagreed about AVIF. Restoring it there
is what unblocks the upload; the extension shorthand and the admin picker's
accept filter are the other two places a .avif file gets turned away before it
reaches that gate. SVG stays excluded.

Closes emdash-cms#2602
@changeset-bot

changeset-bot Bot commented Aug 26, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 9891b85

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 17 packages
Name Type
emdash Patch
@emdash-cms/admin Patch
@emdash-cms/cloudflare Patch
@emdash-cms/sandbox-workerd Patch
@emdash-cms/plugin-mcp-smoke Patch
@emdash-cms/fixture-perf-site Patch
@emdash-cms/perf-demo-site Patch
@emdash-cms/cache-demo-site Patch
@emdash-cms/do-demo-site Patch
@emdash-cms/do-solo-demo-site Patch
@emdash-cms/auth Patch
@emdash-cms/blocks Patch
@emdash-cms/gutenberg-to-portable-text Patch
@emdash-cms/x402 Patch
create-emdash Patch
@emdash-cms/auth-atproto Patch
@emdash-cms/plugin-embeds Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@emdashbot emdashbot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the right fix for the right problem. Restoring image/avif to the upload gate is the minimal, safe way to resolve the regression from #2250 without weakening the SVG exclusion that motivated that earlier security change.

I checked the changed files and traced the relevant call sites:

  • GLOBAL_UPLOAD_ALLOWLIST now includes image/avif; the upload routes in packages/core/src/astro/routes/api/media.ts and api/media/upload-url.ts fall back to this list, and the existing inline-serving routes (routes/api/media/file/[...key].ts, media/image-endpoint.ts, and the plugin artifact route) already list AVIF as a safe inline type, so the upload gate was the only outlier.
  • Both EXTENSION_TO_MIME maps (core and admin) include .avifimage/avif, so field-level allowedMimeTypes using extension shorthand works.
  • The admin upload dialog’s accept attribute and PREVIEW_MIME_TYPES set include AVIF, and the built-in "Images" preset in AllowedTypesEditor includes it too.
  • The changeset (emdash and @emdash-cms/admin patch) is accurate, user-facing, and names the observable behavior and affected audience.
  • The docs table is updated to match the new default allowlist.
  • Tests were added for both the allowlist membership and the extension shorthand expansion, framed as regressions against the media routes’ existing AVIF support.

No new user-facing strings were added, so no Lingui or RTL/Tailwind work is required. No database queries or logged-out routes are affected. The implementation is scoped, consistent, and leaves SVG excluded.

LGTM — no findings.

@ascorbic ascorbic left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

@github-actions

github-actions Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@ascorbic
ascorbic enabled auto-merge (squash) August 26, 2026 14:45
@pkg-pr-new

pkg-pr-new Bot commented Aug 26, 2026

Copy link
Copy Markdown

Open in StackBlitz

@emdash-cms/admin

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/admin@2683

@emdash-cms/auth

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/auth@2683

@emdash-cms/auth-atproto

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/auth-atproto@2683

@emdash-cms/blocks

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/blocks@2683

@emdash-cms/cloudflare

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/cloudflare@2683

@emdash-cms/contentful-to-portable-text

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/contentful-to-portable-text@2683

emdash

npm i https://pkg.pr.new/emdash-cms/emdash@2683

create-emdash

npm i https://pkg.pr.new/emdash-cms/emdash/create-emdash@2683

@emdash-cms/gutenberg-to-portable-text

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/gutenberg-to-portable-text@2683

@emdash-cms/plugin-cli

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-cli@2683

@emdash-cms/plugin-types

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-types@2683

@emdash-cms/registry-client

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/registry-client@2683

@emdash-cms/registry-lexicons

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/registry-lexicons@2683

@emdash-cms/registry-moderation

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/registry-moderation@2683

@emdash-cms/registry-verification

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/registry-verification@2683

@emdash-cms/sandbox-workerd

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/sandbox-workerd@2683

@emdash-cms/x402

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/x402@2683

@emdash-cms/plugin-ai-moderation

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-ai-moderation@2683

@emdash-cms/plugin-atproto

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-atproto@2683

@emdash-cms/plugin-audit-log

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-audit-log@2683

@emdash-cms/plugin-color

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-color@2683

@emdash-cms/plugin-embeds

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-embeds@2683

@emdash-cms/plugin-field-kit

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-field-kit@2683

@emdash-cms/plugin-forms

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-forms@2683

@emdash-cms/plugin-webhook-notifier

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-webhook-notifier@2683

commit: 9891b85

@hossein-webdev

Copy link
Copy Markdown
Contributor Author

I have read the CLA Document and I hereby sign the CLA

@hossein-webdev

Copy link
Copy Markdown
Contributor Author

recheck

1 similar comment
@hossein-webdev

Copy link
Copy Markdown
Contributor Author

recheck

github-actions Bot added a commit that referenced this pull request Aug 27, 2026
@ascorbic
ascorbic merged commit 3e90689 into emdash-cms:main Aug 27, 2026
50 of 51 checks passed
@emdashbot emdashbot Bot mentioned this pull request Aug 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[AVIF] Upload failed: File type not allowed

2 participants