Community-friendly degraded lockdown — explicit-call ES module. Drop-in for mainstream tooling (Next.js, Astro, Vite, webpack) with no special configuration. A subset of
base.jsthat omits the lockdowns incompatible with framework runtimes.
Source packages/front/fw/src/sanity/community.js | Type ES module, explicit call | Worker-safe no
ES module exporting applyCommunity(), an explicit-call function. It does not resolve via runtime.resolve(). Call it before application code to apply framework-tolerant restrictions. Unlike base.js it leaves framework-critical globals (Math.random, history, performance, JSON, innerHTML, prototypes) untouched so that Next.js, Astro, and other mainstream tools run unmodified.
For untrusted-code or hostile-environment hardening, use base.js instead.
Usage
import { applyCommunity } from '@awacloud/fw/sanity/community';
applyCommunity(); // must be called before all application code
import { runtime } from '@awacloud/fw';
import modules from '@awacloud/fw/core/modules';
runtime.registerAll(modules);
For zero-bundler deployment:
<script src="packages/front/fw/dist/build/sanity-community-classic.min.js"></script>
<script type="module" src="src/main.js"></script>
API
applyCommunity() applies a subset of the base.js measures, omitting those incompatible with framework runtimes. Returns { applied: boolean, reason?: string, steps: string[] } — the step list records which measures ran.
KEEP vs DROP table
base.js measure |
community | Why |
|---|---|---|
Block window eval, alert, confirm, prompt, open |
KEEP | XSS / unwanted-dialog hardening; frameworks don't use these at runtime |
Block window Function, import, importScripts, Reflect |
DROP | Bundler runtimes / libs rely on dynamic import, Function, Reflect |
Block document write, writeln, open, close, execCommand, execScript, evaluate, createContextualFragment |
KEEP | document.write-style injection; not used by Next/Astro hydration |
Block document implementation |
DROP | Some libs read document.implementation; low XSS value |
Block Element.prototype setHTML, evaluate |
KEEP | Harmless to frameworks |
Block document.domain (set) |
KEEP | Harmless, good hardening |
wrapTimingFunctions (reject string setTimeout/setInterval/rAF) |
KEEP | Pure string-eval XSS; frameworks always pass functions |
blockDangerousElements (iframe/object/embed src/srcdoc/… set → throw) |
KEEP | Retained XSS hardening |
disableDebugger (window.debugger shim, stackTraceLimit) |
KEEP | Harmless |
freezePrototypes() |
DROP | Frozen Object/Array/Function/…prototype + non-writable constructor breaks framework hydration/instanceof/subclassing |
Block history.pushState/replaceState/go/back/forward |
DROP | Breaks Next.js <Link> / Astro SPA navigation |
Block performance.now/mark/measure/getEntries |
DROP | React scheduler and framework perf marks depend on these |
Block crypto.randomUUID |
DROP | Used by some libs/frameworks |
redirectPropertySetter (innerHTML → innerText, …) |
DROP | Corrupts hydration / dangerouslySetInnerHTML / templating |
blockJSONParsing (reviver/replacer-fn + freeze JSON) |
DROP | Framework data serialization uses JSON heavily |
blockPerformanceAPIs (Date.now rounding) |
DROP | Coarse Date.now breaks timing/animation/scheduler |
blockMathRandom (Math.random → throw) |
DROP | Countless libs call Math.random; throwing breaks them |
Result: community.js keeps a meaningful injection-hardening posture (no eval, no string-timer eval, no document.write/execCommand, no dangerous element src injection) while leaving intact every runtime semantic Next/Astro rely on (prototypes, history, performance, Math.random, JSON, Date.now, innerHTML).
SSR / Server-side rendering
community.js is browser-only. When evaluated in a non-browser environment (Node.js, Bun, edge workers, Next.js / Astro prerender) the SSR guard fires immediately and the entire body is skipped:
if (typeof window === 'undefined' || typeof document === 'undefined') return;
This makes it safe to bundle and import in universal (isomorphic) code without wrapping in a typeof window !== 'undefined' check at the call site.
When to use base.js instead
Use base.js when:
- Running in a controlled environment (SDE/SDC runtime) where framework compatibility is not required.
- Evaluating untrusted user code and you need the full lockdown (frozen prototypes, blocked
Math.random, blockedhistory, restricted JSON). - You need the
paranoia.jssuperset for complete hostile-environment hardening.
community.js is intentionally weaker than base.js. The tradeoff is explicit: you gain framework compatibility at the cost of a reduced attack surface.
Notes
- The ES module source
src/sanity/community.jsmust be imported andapplyCommunity()must be called. Bare import (without calling) has no effect. - For zero-bundler deployment, use the built classic artifact
dist/build/sanity-community-classic.min.js, which self-applies on load via<script src>. LOG_ATTEMPTS = true(current source value): each blocked attempt produces aconsole.warnwith stack trace.STACK_TRACE_LIMIT = 10:Error.stackTraceLimitis reduced to 10 frames (V8/Chrome only).- SSR / Server-side rendering:
applyCommunity()includes the SSR guard internally — calling it in a non-browser environment (Node.js, Bun, edge workers) returns{applied: false, reason: 'non-browser-realm'}and makes no changes.
See also
- sanity/base — full strict lockdown (use for untrusted-code / hostile environments)
- Security guide — threat model and lockdown rationale