Script Policy
Custom scripts are disabled by default and must be enabled by a tenant administrator.
Why Scripts Are Opt-In
A custom script (onFormLoad, onBeforeSave, and functions called from rules and buttons) is JavaScript that runs in the browser of every form user with their permissions and is not sandboxed. Anyone allowed to modify the form configuration could therefore run arbitrary code in other users' sessions. For this reason, scripts do not run unless a tenant administrator explicitly allows them.
Expressions remain safe without enabling the policy. Formulas in the setExpression rule action and button actions are evaluated by a custom parser that does not use eval or new Function and has no access to window, fetch, or anything outside field values. Expressions, rules, and buttons therefore work even when the policy is disabled. See Expressions & Formulas.
The Policy and Its Values
The policy is a tenant Storage Entity in the tenant App Catalog. The primary key is FormCraft365_ScriptsPolicy (values allow / deny). The legacy key SpfxFormCustomizer_ScriptPolicy (values enabled / disabled) is also read, but only when the new key does not exist in the tenant at all. The new key always takes precedence: deny in the new key disables scripts even if enabled is set in the old key.
| Value | Result |
|---|---|
allow or enabled (case-insensitive, surrounding whitespace ignored) | Scripts are allowed. |
deny, disabled, or any other value (including typos like off or no) | Scripts are disabled. |
| Value missing (neither key exists) | Scripts are disabled (default state, opt-in). |
| Error while reading | Scripts are disabled (fail closed). |
Enabling scripts is always an explicit administrator decision. A tenant that has never configured the policy has scripts disabled.
Enabling and Disabling
In the Designer
- In the designer, open Security and the Custom Scripts section.
- The Allow custom scripts tenant-wide toggle is visible and usable only by users who have write access to the tenant App Catalog (catalog site admins). Others see only the status and the command to pass to an administrator.
- Confirm the change in the risk warning dialog (Confirm change). This writes
allowordenyto theFormCraft365_ScriptsPolicykey. - The message "The change will take effect after reloading the form (within 15 minutes at most)" is displayed.
Via PowerShell
Connect-PnPOnline -Url "https://<tenant>.sharepoint.com/sites/appcatalog" -Interactive
# Allow
Set-PnPStorageEntity -Key FormCraft365_ScriptsPolicy -Value allow -Scope Tenant
# Deny (also overrides the legacy key)
Set-PnPStorageEntity -Key FormCraft365_ScriptsPolicy -Value deny -Scope Tenant
# Revert to default (disabled): remove both keys
Remove-PnPStorageEntity -Key FormCraft365_ScriptsPolicy
Remove-PnPStorageEntity -Key SpfxFormCustomizer_ScriptPolicy
For an administrator without write permissions to the App Catalog, the designer provides both the allow and deny commands to pass along.
15-Minute Cache
The browser caches the result of the last successful read for 15 minutes (localStorage, key _fc_scrpol_<tenantId>). Therefore, a change may take up to 15 minutes to reach users. You can see it immediately by deleting _fc_scrpol_* keys from localStorage and reloading the page. A read error does not extend the cache duration: on error, scripts are disabled.
Behavior When Disabled
- No script is compiled or executed. The single gate is the
runScriptfunction in the renderer, which checks the policy foronFormLoad,onBeforeSave, and function calls. - Rules and formulas continue to work. Custom buttons render and execute their non-script actions (
setValue,setFieldValue,setExpression, submit). ThecallFunctionaction is skipped. - Form administrators see an info banner in the form: "Custom scripts are disabled on this tenant…". Regular users see nothing.
- Existing scripts can still be deleted in the designer (adding and editing are locked), allowing you to clean up the configuration so the warning disappears.
onBeforeSavedoes not run when scripts are disabled and saving is not blocked (the administrator sees a warning about this). To block saving, use rules with theblockSaveaction.- In debug mode, skipping is logged to the console as
[FC debug] script skipped: tenant policy disabled (…). See Debug Mode.
Risks After Enabling
The policy applies tenant-wide to all forms. A script running in a form can read and modify data in the session of the user who opened the form. Enable it only after verifying that only trusted designers can modify form configurations (see Permissions: locked storage and the "site owners" role).
- Sandboxed script execution is not yet part of the product.
- Scripts are compiled dynamically. A strict browser or tenant CSP may block execution (
unsafe-eval); see below. - If considering enabling scripts for a single form, evaluate whether rules and expressions—which do not require the policy—can achieve the same result.
Accepted Risk: Site Collection App Catalog
Storage Entities are read via /_api/web/GetStorageEntity. This endpoint may return a value from a site collection App Catalog before the tenant one. A site collection administrator with their own App Catalog could thus enable scripts for their site. The same applies to reading the license key. The tenant catalog is intentionally not read directly because regular users cannot read it. This is an accepted risk: do not use site collection App Catalogs where this would be unacceptable.
CSP Errors and unsafe-eval
If the policy is enabled, but a script does not run and an error appears in the form (or console), refer to the table below:
| Message | Cause |
|---|---|
| The tenant or browser security policy (CSP) blocks dynamic script execution (unsafe-eval). | The environment prohibits new Function. Scripts will not work here; use rules and expressions instead. |
| Script compilation error (invalid syntax). | Syntax error in the script code. Fix it in the designer's script editor. |
| Script error: … | Runtime exception in the script. Debug mode prints the details. |
Troubleshooting steps: Troubleshooting, scripts are not working. Writing scripts is described in Scripts.