# Untrusted HTML Hosting Security Review

Canonical guide: https://slidesfly.com/blog/host-untrusted-html-safely
Version: 2026-08-24

Use this checklist to review a system that stores and renders complete user-supplied HTML, CSS, and
JavaScript. It does not certify the system, replace a penetration test, or authorize publication.

Result rule: every required item must be `PASS`; use `N/A` only with a written reason. Record the
exact code revision, environment, URLs, browser, artifacts, and reviewer so another person can
reproduce the evidence.

## Review identity

- System and environment:
- Code revision / deployment:
- Trusted application origin:
- Untrusted content origin:
- Test artifact and hash:
- Browser / version:
- Reviewed at:
- Reviewer:
- Scope exclusions:

## 1. Threat model and content contract

- [ ] PASS / FAIL / N/A — Executable HTML is explicitly classified as untrusted active content.
  Evidence:
- [ ] PASS / FAIL / N/A — The model covers credential/DOM access, navigation, phishing, outbound
  requests, cross-artifact access, resource exhaustion, and stale-content delivery.
  Evidence:
- [ ] PASS / FAIL / N/A — The system distinguishes trusted-DOM rich-text sanitization from isolated
  execution of complete HTML documents.
  Evidence:
- [ ] PASS / FAIL / N/A — Accepted file shapes, capabilities, sizes, and unsupported behaviors are
  documented.
  Evidence:

## 2. Origin and route isolation

- [ ] PASS / FAIL / N/A — Uploaded code does not execute on the application/session origin.
  Evidence:
- [ ] PASS / FAIL / N/A — The content origin does not expose login, account, billing, admin, or
  write APIs.
  Evidence:
- [ ] PASS / FAIL / N/A — Application session cookies are not available to the content origin.
  Evidence:
- [ ] PASS / FAIL / N/A — Production cannot enable a local preview/domain-override bypass.
  Evidence:
- [ ] PASS / FAIL / N/A — Raw file, download, embed, custom-domain, and new-tab paths preserve the
  intended trust boundary.
  Evidence:

## 3. Browser runtime isolation

- [ ] PASS / FAIL / N/A — The exact iframe or CSP sandbox configuration is visible and reviewed.
  Evidence:
- [ ] PASS / FAIL / N/A — `allow-same-origin` is absent, or every artifact has a demonstrably unique,
  low-privilege origin with equivalent isolation tests.
  Evidence:
- [ ] PASS / FAIL / N/A — Top-level navigation is blocked unless a documented, tested requirement
  justifies a narrower exception.
  Evidence:
- [ ] PASS / FAIL / N/A — Every restored form, popup, download, modal, storage, clipboard, fullscreen,
  orientation, or pointer capability has a reason and abuse test.
  Evidence:
- [ ] PASS / FAIL / N/A — CSP constrains scripts, connections, frames, forms, media, fonts, and other
  resources according to the artifact contract.
  Evidence:
- [ ] PASS / FAIL / N/A — Parent/frame messaging validates the sender/window, message shape, and size;
  it never evaluates messages as code or inserts them through unsafe trusted-DOM sinks.
  Evidence:

## 4. Upload and archive controls

- [ ] PASS / FAIL / N/A — Extension, filename, HTML shape, request size, and decoded size are validated
  without trusting request `Content-Type` alone.
  Evidence:
- [ ] PASS / FAIL / N/A — Object keys are generated or normalized independently from user filenames.
  Evidence:
- [ ] PASS / FAIL / N/A — Archives reject absolute paths, backslashes, null bytes, and `..` traversal.
  Evidence:
- [ ] PASS / FAIL / N/A — Archive duplicate paths cannot make the scanner inspect different bytes
  from those ultimately served.
  Evidence:
- [ ] PASS / FAIL / N/A — File count, compressed bytes, total expanded bytes, and plan limits are
  enforced before unbounded extraction or storage.
  Evidence:
- [ ] PASS / FAIL / N/A — Every executable/text asset is validated or scanned, not only `index.html`.
  Evidence:
- [ ] PASS / FAIL / N/A — Reputation failures/timeouts remain `unscanned` or `unavailable`; they are
  not recorded as clean verdicts.
  Evidence:

## 5. Storage and delivery policy

- [ ] PASS / FAIL / N/A — Stored objects are private, or every public object path is mediated by an
  authoritative policy layer.
  Evidence:
- [ ] PASS / FAIL / N/A — Current visibility, expiry, protection, moderation, and version state are
  checked before bytes are served.
  Evidence:
- [ ] PASS / FAIL / N/A — Entry files and all bundled assets follow the same access decision.
  Evidence:
- [ ] PASS / FAIL / N/A — Historical or replaced object paths cannot be guessed to bypass current
  version policy.
  Evidence:
- [ ] PASS / FAIL / N/A — Cache lifetime cannot outlive deletion, expiry, protection, quarantine, or
  visibility changes.
  Evidence:
- [ ] PASS / FAIL / N/A — Policy-service or storage errors fail closed and are distinguishable from
  ordinary access denial.
  Evidence:

## 6. Lifecycle and response

- [ ] PASS / FAIL / N/A — Clean-session tests prove expiry, deletion, quarantine, protection, and
  version replacement revoke the intended reader and object paths.
  Evidence:
- [ ] PASS / FAIL / N/A — A visible report path, moderation states, triage owner, and quarantine
  procedure exist.
  Evidence:
- [ ] PASS / FAIL / N/A — Security disclosure instructions and a monitored contact are published.
  Evidence:
- [ ] PASS / FAIL / N/A — Alerts distinguish structural rejection, risk flags, reputation hits,
  policy outages, fetch failures, reports, and operator actions.
  Evidence:
- [ ] PASS / FAIL / N/A — Recovery and rollback are tested without restoring an unsafe or expired
  artifact to public delivery.
  Evidence:
- [ ] PASS / FAIL / N/A — Public claims state residual risk and do not promise “100% safe,” “zero
  risk,” or certification without defined scope and evidence.
  Evidence:

## Review result

- Required checks passed:
- Required checks failed:
- N/A checks with reasons:
- Residual risks:
- Remediation owner and due date:
- Decision: PASS / FAIL
- Reviewer sign-off:
