Skip to main content
Rive files can include code: AnimaScript and Luau scripts, and WGSL shaders. Rive runtimes treat that code as untrusted. It runs in a sandbox and can only do what Rive allows. It can’t reach the device’s files or the rest of your app, and it reaches the network only if your app turns on script fetch.
AnimaScript is the recommended language for new scripts. Luau is deprecated: Luau scripts keep running on every Rive runtime, but new scripting features land in AnimaScript. This page covers both.

FAQs

How Rive approaches script security

  • The sandbox is the safety boundary. Rive does not depend on trusting the person who made a file. Code in a file runs inside a sandbox that limits what it can reach, so even a harmful script cannot reach anything Rive doesn’t allow.
  • Scripts start with nothing. Rive adds each ability on purpose, as an API it controls: drawing, View Models, input, audio, and the objects in the script’s own file. Network requests come only through script fetch, which your app turns on. A script can’t use anything Rive didn’t give it.
  • Signing proves where code came from, not that it is safe. Rive requires a signature only where the engine cannot check code itself: Luau bytecode and compiled shaders. Rive compiles that code on its own servers, so it signs only code it produced. AnimaScript needs no signature, because the WebAssembly sandbox checks and contains every module.
  • A script that breaks the rules stops with an error. Your app keeps running. Time limits stop most script calls that run too long, but not all of them, and a script can still use enough CPU, GPU, or memory to slow or freeze your app. See Time limits for what each limit covers.
  • Your app decides. A file cannot act on your app directly. It can only hand values to your code, and your code decides what to do with them.

What code in a file can do

Everything in a Rive file, code included, works inside the view your app gives it. AnimaScript and Luau scripts share the same restrictions. A file can:
  • Draw inside its view. It cannot draw outside the view or change the rest of your app’s UI.
  • Play sounds stored in the file. AnimaScript scripts can also generate sound.
  • React to the input that reaches its view: pointer, keyboard, gamepad, and text entry.
  • Read and change the View Model data your app binds to it.
  • Report events to your app.
Scripts add logic to these abilities. A script can also read the current time, print messages to the debug console, and draw with GPU Canvas shaders. AnimaScript scripts can also run jobs and workers, on background threads where the runtime supports them. If your app turns on script fetch, scripts can also send HTTPS requests to the hosts you allow and read the responses. Neither a file nor its scripts can:
  • Make network requests, unless your app turns on script fetch. Downloads of Hosted assets come from the runtime, and your app controls them. See Hosted assets.
  • Read or write files on the device.
  • Read device data such as location, contacts, photos, camera, microphone, or clipboard.
  • Read app data that you have not bound to the file.
  • Reach other Rive files your app has loaded. Each file runs its scripts in its own environment.
  • Load code from outside the file, or create new code while it runs. The exception is decodeFile, on runtimes that support script fetch. See Files that scripts decode.
  • Navigate your app.
  • Open URLs, unless you turn it on. Only the web runtime can do this, using the deprecated automaticallyHandleEvents option. See Open URL events.

How each language is contained

AnimaScript

AnimaScript compiles to WebAssembly, a format designed to run code safely inside a sandbox. The Rive Editor or the Rive CLI compiles your scripts to a WebAssembly module and stores it in the .riv file.
  • On the web, the runtime loads the module into the browser’s own WebAssembly engine, the same sandbox that browsers use for all WebAssembly.
  • Outside the browser, Rive runs modules with WAMR, an open-source WebAssembly runtime, under the same sandbox rules. A .riv file carries these modules only as WebAssembly bytecode, never as machine code, and the runtime rejects anything else. Depending on the platform, a module runs as machine code compiled ahead of time, or on WAMR’s interpreter. The Apple and Android runtimes do not run AnimaScript yet. See Where Scripts Run.
Inside the sandbox:
  • A module can call only the functions Rive provides. It has no other way to reach the system.
  • Every memory access stays inside the module’s own memory. An access outside it, or a bad pointer passed to a Rive API, stops the module with an error.
  • Threads and audio processors run in sandboxed modules of their own. Any memory they share belongs to the same file’s scripts.
AnimaScript is not signed today. Its safety comes from the sandbox, which checks and contains every module, whoever built it. In AnimaScript source, raw memory access must sit in functions marked unsafe, so a reviewer can find it with a text search. Even there, it reaches only the module’s own memory. See The Unsafe Gate.

Luau

Rive runs Luau scripts in a sandboxed Luau virtual machine with a reduced standard library:
  • Base functions, without loadstring
  • table, math, string, utf8, buffer, and bit32
  • os, limited to clock, date, difftime, and time
There is no io, package, or debug library. Built-in libraries and globals are read-only, and require finds only scripts in the same file. The Luau virtual machine assumes that the bytecode it runs came from the Luau compiler, which is why Luau recommends signing compiled code. Rive runtimes run Luau bytecode only if its signature is valid. See What signing guarantees.

Shaders

AnimaScript and Luau scripts can both draw with GPU Canvas shaders written in WGSL. Rive’s servers compile and sign shaders when you export, and runtimes refuse shader code without a valid signature. A shader works only with the buffers and textures its script gives it.

Time limits

  • AnimaScript: every call into a script runs under a time budget, 200 ms in the runtimes. Native runtimes enforce it with a timer. In browsers, a call can be stopped only if the module was built with fuel checks. Debug builds always include them. Optimized builds, which every publish makes, include them only with wasmFuel: true. Without fuel checks, a script that never returns hangs the page. Builds made with dangerouslyFast have no time budget at all. Background jobs and workers have no time limit; they run until they finish or the runtime stops them. See Build Settings.
  • Luau: Rive runtimes interrupt a Luau script call that runs longer than 200 ms. A script written to get around the interrupt can keep running.
Treat these limits as protection against mistakes, not against attacks. A file built to cause harm can still use enough CPU, GPU, or memory to freeze or crash your app.

What signing guarantees

Rive signs compiled Luau scripts and shaders. When you export a file from the Rive Editor, or publish one with the Rive CLI, Rive’s servers compile the source and sign the result. Rive compiles the code itself, so it signs only code it produced. Rive keeps the private signing key on its servers. Every Rive runtime that supports scripting carries the matching public key and checks the signature when it loads a file. Code that is unsigned, or that was edited after signing, does not run. The Rive Editor and the Rive CLI run Luau scripts before they are signed, so you can work on them. Runtimes do not.
The signature check is part of the open-source runtime. See text_asset_importer.cpp and File::acceptsScript in file.cpp.

What a signature does not prove

  • Who made the file, or that its scripts are yours. Today, Rive signs every export with the same key, whatever the account or Workspace. Anyone can write Luau scripts in their own Rive account and export them with a valid signature, so a swapped file with someone else’s scripts passes the check. The sandbox limits what those scripts can do. The signature does not.
  • That the rest of the file is unchanged. Today the signature covers only compiled Luau scripts and shaders.

What the signature covers

The signature covers the compiled code of the file’s Luau scripts and shaders. It does not cover the rest of the file, including:
  • Artboards, Timelines, and State Machines
  • Text, images, fonts, and audio
  • Default View Model values and script input values
  • Event settings, such as the address of an Open URL event
  • Which objects use which scripts
  • AnimaScript modules
If someone changes these parts, the runtime cannot detect it. If someone edits a Luau script or shader inside the file, the signature check fails, and the runtime runs none of the file’s Luau scripts and shaders. The rest of the file still plays.

Whole-file signing

Whole-file signing is coming soon. It is planned to cover the entire exported .riv file, AnimaScript modules included, and runtimes are planned to refuse a file whose signature check fails. A change anywhere in the file would then stop it from loading. We’re also working on a way to use the signature to tell which Workspace exported a file. Signing would then prove where a file came from. The sandbox stays the safety boundary.

Protecting files between design and release

Today, any file exported from Rive with Luau scripts or shaders carries a valid signature, so signing cannot tell your files apart from anyone else’s. Protect the path each file takes from the Rive Editor to your users, as you do for your app’s code and other assets. Whole-file signing will help once it ships. Even then, the checks below confirm that a file is the exact one you approved.

Files bundled in your app

iOS and Android require a code signature that covers every file in your app package. After release, nobody can change a bundled .riv file without breaking that signature. The risk comes earlier, when a file passes from design to engineering. To reduce it:
  • Keep approved .riv files in version control, and change them only through code review.
  • Record the SHA-256 hash of each approved file, and check it in your build pipeline.

Files your app downloads

If your app downloads .riv files, check each one before you load it.
1
Serve files over HTTPS from a server you control.
2
Compare the file’s SHA-256 hash with a value built into your app, or verify a signature made with your own key. Don’t fetch the expected hash from the same server as the file.
3
Pass the bytes to the Rive runtime only if the check passes.
To get a file’s hash, run shasum -a 256 your-file.riv on macOS, or sha256sum your-file.riv on Linux.

Network requests, URLs, and navigation

Script fetch

Script fetch lets AnimaScript and Luau scripts call fetch() to send HTTPS requests and read the responses, for example to load live data or download another Rive file. It’s off until your app turns it on, and nothing in a file can turn it on. Script fetch is available today in the web runtime and the Rive CLI. It’s coming soon to every Rive runtime. Once script fetch is on, the runtime checks every request against these rules:
  • https: URLs only, to host names. No IP addresses, no localhost, no one-word names, and no names that end in .local, .internal, .lan, .localdomain, or .home.arpa.
  • No requests to Rive’s own servers.
  • No cookies, saved credentials, or cache. Scripts can’t set headers such as Cookie, Host, Origin, or Referer. A script can send its own Authorization header.
  • Up to 8 requests at a time per file, and more wait their turn. A file with both AnimaScript and Luau scripts gets 8 for each. Request bodies can be up to 8 MiB, and responses up to 16 MiB by default. Requests time out after 30 seconds by default, and after 60 seconds at most.
  • Outside the browser, requests follow redirects, and every hop passes these rules. On the web, a redirect fails the request.
The host rules look only at the name. On Windows, the Rive CLI also refuses a name that points to a local or private address when it connects directly; through a proxy, that check is up to the proxy. On macOS it doesn’t check the address yet, and on the web that check is up to the browser.
Script fetch covers every file your app loads. Once it’s on, any script can send what it reads to the hosts it can reach, including View Model data your app binds and text typed into its Text Inputs. Turn it on only if you trust every file your app loads, and allow only the hosts those files need.
On the web:
  • allowedHosts lists the hosts scripts can reach. If you leave it out, scripts can reach every host. Your page’s own host works only when you list it by its exact name, since "*" doesn’t include it.
  • The browser’s cross-origin rules decide whether a script can read the response. A simple request still reaches the server either way, so use allowedHosts to limit where requests go.
  • Without proxyUrl, requests leave from your page, so servers that trust your site’s origin answer them, including your own APIs. To keep script requests apart from your site, host the reference proxy page on a separate domain and pass its address as proxyUrl. A proxy page you change sets its own rules for cookies, cache, and redirects.
The request rules are part of the open-source runtime. See net_policy.cpp.

Files that scripts decode

A script can turn bytes into a Rive file with decodeFile and show that file’s artboards in the Rive view. decodeFile comes with every runtime build that supports script fetch, so it works even while script fetch is off. The bytes can come from a download, or from data inside the script. A decoded file runs its scripts in a sandbox of its own, under the same rules as any other file. Its Luau scripts run only with a valid Rive signature, even in the Rive Editor and the Rive CLI. Its AnimaScript modules need no signature, as in any file. It loads only the assets stored inside it, so it never downloads Hosted assets. Your app never sees these files, so the checks in Files your app downloads can’t cover them. To limit where downloaded files come from, limit the hosts that script fetch can reach.

Hosted assets

In the Rive Editor, you can set an image, font, or audio asset to Hosted. A Hosted asset stays on Rive’s CDN instead of inside the .riv file, and some runtimes download it when they load the file. The web runtime and the legacy Apple and Android runtimes download from an address stored in the file, so a changed file can point that download at any server. Scripts cannot change the address or attach data to the request. For other runtimes, see the Loading Assets page for your runtime.

Open URL events

Apple and Android runtimes do not open URLs from a file. If your code listens for events, it receives Open URL events as data and decides what to do with them. The web runtime opens these URLs only if you set the deprecated automaticallyHandleEvents option to true. It is false by default. Rive runtimes cannot navigate your app or open screens. A file can affect your app only through the events and View Model values that your code reads. If your code navigates, opens URLs, or calls your servers based on those values, check them first, as you would any input from outside your app.

Turning off scripting

Rive runtimes have no setting to turn off scripts for one file or for the whole app. To play Rive files without scripts, use a runtime build that leaves scripting out. These builds run no AnimaScript, Luau, or shaders. Files still load and play, but anything a script drives stops working.

Recommendations for apps that handle sensitive data

  1. Control where files come from. Bundle files in your app when you can, and check every downloaded file before you load it.
  2. Bind only the data a file needs. Scripts can read every View Model property your app binds to their file. Never put passwords, tokens, or full card numbers in a View Model.
  3. Use native text fields for secrets. Scripts can read what users type into a Text Input in their file.
  4. Keep secrets out of files. A .riv file is not encrypted. Anyone who has the file can inspect its contents, including compiled scripts and any text in them.
  5. Treat what a file sends back as untrusted input. Check events and View Model values before you act on them. For URLs and screens, accept only values from a list you define.
  6. Turn off what you don’t use. If you don’t use Hosted assets, turn off their download. Leave script fetch off unless your files need it, and allow only the hosts they need. Leave automaticallyHandleEvents off on the web. If your files have no scripts, use a runtime without scripting.
  7. Ask for fuel checks on the web. If your web app plays AnimaScript files from outside your team, ask for files built with wasmFuel: true, so the browser can stop a runaway script. Don’t ship files built with dangerouslyFast unless you trust their source.
  8. Keep your Rive runtime up to date to get security fixes.

Security resources

  • Open-source runtimes. The Rive runtimes are open source under the MIT license, so your team can review the code your app runs: rive-runtime (the C++ core, including the signature check and both scripting engines), rive-ios, rive-android, and rive-wasm.
  • AnimaScript. Where Scripts Run explains how AnimaScript runs on each platform and how its time budgets work.
  • SOC 2 Type II. Part of the Enterprise plan.
  • Reporting a vulnerability. Contact us privately through the support form. Please don’t report security issues in the community forum or in GitHub issues.