diff --git a/packages/iios-service/src/media/media.controller.ts b/packages/iios-service/src/media/media.controller.ts
index 666886f..87b1b32 100644
--- a/packages/iios-service/src/media/media.controller.ts
+++ b/packages/iios-service/src/media/media.controller.ts
@@ -5,6 +5,9 @@ import { SessionVerifier } from '../platform/session.verifier';
import { PresignDownloadDto, PresignUploadDto } from './media.dto';
import type { MessagePrincipal } from '../identity/actor.resolver';
+/** Types that can execute script if a browser renders them top-level — served as downloads only. */
+const SCRIPTABLE_MIMES = new Set(['text/html', 'application/xhtml+xml', 'image/svg+xml', 'text/xml', 'application/xml']);
+
@Controller('v1/media')
export class MediaController {
constructor(
@@ -37,6 +40,12 @@ export class MediaController {
async blob(@Param('token') token: string, @Res() res: Response) {
const { data, mime } = await this.media.get(token);
res.setHeader('Content-Type', mime);
+ // Never let the browser MIME-sniff an upload into something executable.
+ res.setHeader('X-Content-Type-Options', 'nosniff');
+ // Script-capable types must not render inline from our origin (stored-XSS) — force a download.
+ // Images/video/audio/pdf stay inline so the app can preview them. Note
/