Scanner rule codes
Five whole-word regular expressions are run over raw script text. A match on any one of them is a
severity: "error" issue carrying the code below, and it stops the mod being registered or served. They
are declared as bannedScriptPatterns in packages/shared/src/modManifest.ts and mirrored as
SANDBOX_SCANNER_RULES in apps/server/src/githubScanner.ts.
These five are the script-content codes. The scanner emits many more codes for paths, assets, media, manifests, JSON, packs and dependency graphs — What gets rejected is the complete list, and Fixing a rejection is the per-code repair guide. This page is the value table for the five that read your code.
The values#
| Code | Tokens that reject the file | Message | Contexts it is checked in | Surfaces it applies to |
|---|---|---|---|---|
dom-access |
document window parent top opener |
Scripts cannot access DOM/window globals. | GitHub scan · serve time · local editor draft | Mod entry.script and compiled table scripts |
network-access |
fetch XMLHttpRequest WebSocket EventSource |
Scripts cannot open arbitrary network connections. | the same three | both |
storage-access |
localStorage sessionStorage indexedDB cookie |
Scripts cannot access browser storage or cookies. | the same three | both |
dynamic-code |
eval Function importScripts |
Scripts cannot use dynamic code loading. | the same three | both |
timer-loop |
setInterval requestAnimationFrame |
Scripts must be deterministic and event-driven. | the same three | both |
Every pattern is case-sensitive: Function is banned and function is fine; Top is fine and top
is not.
The two facts that catch people#
Comments are scanned. There is no lexer and no parse — the regex runs over raw text, so a comment,
a string literal and an identifier are indistinguishable. // draw the top card rejects the file.
Table scripts are scanned too. validateSceneScriptSafety runs the same five patterns over a scene
script's compiled body, and the editor's transpile does not strip comments, so the same comment rejects
a whole scene.
By design. The scanner's own note states the trade: "false positives are acceptable (mod authors can adjust scripts), while false negatives are treated as boundary risks and should trigger a rule update." This is a security boundary and it is not expected to loosen.
\bneeds a non-word character on both sides, sotopCard,deckTop,parentZone,parentId,fetchCountandwindowSeatare all safe — rename or rephrase. Per-rule workarounds are on Script safety. See Known limitations.
The one that cost a real feature, and what was done about it#
dom-access includes the bare word top, and three of the nine screen anchors a mod can give a UI element
are "top-left", "top-center" and "top-right". Because " and - are both non-word characters, the
word boundary fires inside the string, so a mod script containing any of those three was rejected outright.
The rule was not changed. Matching inside string literals is what makes it useful — it is what catches
self["top"] — and narrowing it would swap a false positive for a false negative, which the scanner's own
note calls the unacceptable direction. Instead presentation.anchor gained three input aliases:
upper-left, upper-center and upper-right, normalized to the canonical top-* values before anything
is stored. Write the alias in a mod script and read the canonical value back.
See TableUiWidgetType.
Where else these five appear#
The same five patterns are what undeclared-capability is not: capability validation is a separate check
with its own twelve detector regexes and its own code. A script can pass all five patterns and still be
rejected for calling an api method its manifest did not declare.
See Mod capabilities.
See also#
- What gets rejected — every rule code, not only the script ones.
- Script safety — all five patterns with per-rule workarounds.
- Fixing a rejection — what to change, code by code.
- ModCapability — the other thing a script is checked against.
- Sandbox limits — the language subset behind the rules.
