feat: add multi-engine regex flavour support

This commit is contained in:
2026-07-27 11:43:51 +02:00
parent 7079cde15f
commit 7f3a91ad37
340 changed files with 643286 additions and 483 deletions

View File

@@ -23,10 +23,67 @@ untrusted.
identities. Pattern, subject, flags and replacement remain string data passed
to the fixed application bridge; no user-supplied Python source is evaluated.
Native code-point boundaries are checked before conversion to editor UTF-16.
Bounded replacement bytes use canonical base64 rather than content-dependent
JSON escaping; declared length, request cap and canonical UTF-8 are validated
before the output is exposed.
- Java starts only after the worker verifies the TeaVM bridge ABI, engine
identity and compiled self-test. It exposes only fixed bounded
`Pattern`/`Matcher` entry points; no JVM, Java class loading or user-supplied
JavaScript is available. The runtime is TeaVM, not OpenJDK.
- PHP starts only after the worker verifies PHP 8.5.8, PCRE2 10.44 and the
fixed bridge ABI. User values are JSON data written to a private virtual
filesystem; the bridge chooses a safe delimiter, allowlists modifiers and
invokes only fixed `preg_*` operations.
- The legacy Perl worker writes exact-key, byte-bounded JSON to a fixed MEMFS
request path and invokes only the constant `RegexTools::run_request()` entry
point. The bridge uses `no re 'eval'`, rejects `(?{...})` and `(??{...})`
outside escaped literals/classes, pre-tokenizes its non-executable
replacement grammar and streams bounded UTF-8 chunks from native match spans.
Successful output uses a separate fixed binary file, never the JSON response;
the worker verifies exact bytes, limit and canonical UTF-8 before decoding
it. Replacement stops at the match/capture-row bound and leaves the
unprocessed subject tail unchanged. WebPerl 0.09-beta's unmodified generated
loader contains one `eval(code)` site in an optional
JavaScript-interoperability import; the fixed bridge never loads or calls it.
The checksummed asset passes the browser CSP smoke without broad
`'unsafe-eval'`.
- Ruby evaluates only the fixed application bridge during worker startup.
Pattern, subject, flags, limits and replacement travel in one bounded,
length-prefixed file in the worker-local WASI memory filesystem. Native
`String#gsub`/`String#sub` block iteration cannot materialize expanded user
output: a fixed CRuby 4.0.0-compatible expander stops at the byte limit and
writes that prefix to a separate bounded file. The inert JSON response
contains metadata only and is assembled without per-code-point arrays. No
user value is interpolated into source or sent through ruby.wasm's
`RubyVM.wrap`/`toJS` JavaScript-eval conversion path. Unpaired browser
surrogates are rejected before UTF-8 encoding. Ruby cold startup passes the
strict-CSP release browser gate.
- C++ accepts only structured fixed Embind calls and is compiled with
Emscripten `-sDYNAMIC_EXECUTION=0`; the generated module is checked for
dynamic-source construction. Its libc++-compatible replacement expander
appends directly through the UTF-8 byte cap and is parity-checked at load.
Embind returns a structured JavaScript string rather than JSON, so there is
no escape amplification; the 64 MiB native buffer and its bounded UTF-16
conversion are the explicit peak-output copies.
- Go and Rust accept JSON data only through fixed exports. Each validates its
request and enforces pattern, subject, result and output caps inside
WebAssembly. Adapters measure exact encoded request bytes; the native request
cap covers worst-case sixfold JSON escaping for every accepted string field,
so control-heavy values retain the documented decoded field limits. Their
native-compatible replacement token streams stop at the output cap without
allocating a whole capture expansion. Bounded UTF-8 output crosses the JSON
bridge as fixed 4:3 base64 rather than content-dependent escaped text. Rust
additionally caps compiled-regex and DFA storage.
- .NET accepts bounded JSON only through fixed `[JSExport]` methods and never
evaluates user input as managed or JavaScript source. A native regex timeout
complements the supervisor timeout. Its fixed replacement parser streams
native-compatible token fragments through the UTF-8 byte cap, verifies
parity with `Match.Result` at load and transports output as canonical base64
to avoid JSON escaping amplification. The shipped .NET host contains runtime
debugging machinery, but normal production startup disables debugging and
is verified under the documented CSP.
- Scala compatibility shares the TeaVM Java bridge. It introduces no Scala
runtime, dynamic compiler or additional execution surface.
- Every bundled engine directory has a closed file set, deterministic
metadata/checksums and licence material verified both before installation and
in `dist/`. Runtime imports and fetches resolve only against the same-origin
@@ -86,12 +143,15 @@ untrusted.
closed. Subjects and results are ephemeral and never uploaded or persisted.
- No backend, uploads, telemetry, remote corpus URL, CDN, remote font,
arbitrary command line or unsafe HTML rendering exists. Application code
does not evaluate user-controlled JavaScript or Python. The generic generated
Pyodide loader contains an Emscripten dynamic-link branch that uses
JavaScript `eval`, but the shipped self-contained CPython/stdlib path does not
exercise it and loads under the CSP below without broad `'unsafe-eval'`.
does not evaluate user-controlled source in any language. The generic
generated Pyodide loader contains an Emscripten dynamic-link branch that
uses JavaScript `eval`, while the legacy WebPerl loader contains the optional
interop site described above. Neither shipped fixed execution path exercises
those branches, and both load under the CSP below without broad
`'unsafe-eval'`.
The engine-enabled build needs a CSP equivalent to:
Every enabled profile, including a cold Ruby start, passes the release CSP
equivalent to:
```text
default-src 'self';
@@ -107,11 +167,12 @@ base-uri 'none';
form-action 'none';
```
The Toolbox shell currently requires inline styles. Corpus ZIP generation,
PCRE2, Pyodide and TeaVM use self-hosted modules/assets and local workers under
the existing `worker-src` and `connect-src` policy. Broad `'unsafe-eval'` is not
required; `'wasm-unsafe-eval'` remains required for the two WebAssembly
runtimes.
The Toolbox shell currently requires inline styles. Corpus ZIP generation and
every engine pack use self-hosted modules/assets and local workers under the
existing `worker-src` and `connect-src` policy. Broad `'unsafe-eval'` must not
be added to accommodate an engine. The release gate blocks any future profile
that fails this strict-CSP browser matrix. `'wasm-unsafe-eval'` remains required
for the WebAssembly runtimes.
Report vulnerabilities privately to the repository owner before public issue
details are posted.