Self-checking scoreboard
Safe parser ≡ current engine, on every operation
Each shipped/cookbook operation is evaluated over several interval values Y by both the current
new Function() path and the new safeEval parser. They must agree to the last decimal. This is the
guarantee that hardening changes nothing a user sees.
| Operation | Y=1319 | Y=1656 | Y=6940 | Result |
|---|
Injection payloads: executed vs blocked
The same strings fed to both engines. The current new Function() path (and the rewrites' regex-allowlist)
treats these as code; the parser rejects anything outside the grammar — numbers, Y, the four constants, the
oph_* functions, and + − * / ( ). A blocked in the right column is a win.
Payload (after X2+) | What it targets | new Function() | safeEval |
|---|
Why the current regex filter isn't enough
The PSYFR rewrites gate input with a character-allowlist (blank the known tokens, reject leftover letters). That stops casual misuse, but it's a denylist in front of a live compiler — one new function alias, or a payload built only from allowed characters, and it's back to arbitrary code. A parser that only ever produces an AST it knows how to walk has no such escape hatch.
Type an operation
Anything legal computes with Y = 1656. Anything outside the grammar is rejected with a reason — never executed.
# The whole safe evaluator is ~90 lines, no dependencies, no eval/new Function.# Grammar: expr := term (('+'|'-') term)* term := factor (('*'|'/') factor)*# factor := number | 'Y' | CONST | func '(' expr ')' | '(' expr ')' | '-' factor