Netty 4.1.133.Final introduced a regression in MqttDecoder while fixing
CVE-2026-44248: when multiple MQTT packets are present in the same
cumulation buffer, the per-message size check used the total buffer size
instead of the current packet's declared remaining length. Valid in-limit
packets get rejected with TooLongFrameException("message length exceeds
65536: <small number>"). Fixed upstream by netty/netty#16787 and ported
to 4.1 as netty/netty@30f8f284db, released in 4.1.134.Final.
Exposes the dashboard entities-limit check as a reusable public method
so callers outside the validator can enforce the same limit without
duplicating the apiLimitService logic.
Two test layers covering the controller surface that the JVN PoC uses:
Java unit (Spring MockMvc):
RuleChainControllerTest#testScriptForbiddenForCustomer asserts a
customer JWT against POST /api/ruleChain/testScript returns 403,
locking in the existing @PreAuthorize('TENANT_ADMIN') guard.
Black-box (live docker-compose):
JsExecutorSandboxIsolationTest#testRuleChainScriptCannotReachHostProcess
posts the JVN exploit payload as a tenant admin and asserts the
response carries error='process is not defined'. End-to-end through
tb-node -> Kafka -> tb-js-executor with use_sandbox=true.
Registered the new org.thingsboard.server.msa.security package in
the connectivity TestNG suite so the black-box runner picks it up.
Added a thin TestRestClient.testRuleChainScript() helper.
Four test cases under describe('js-executor'):
- sandbox isolates args from host realm (JVN#16937365 — regression guard)
- sandbox passes string args through unchanged
- non-sandbox path does not isolate from host realm (documented contract)
- non-sandbox path passes string args through unchanged
Tests use Node's built-in node:test + node:assert (zero new devDependencies;
ts-node was already there). Two npm scripts:
test — spec output for local dev
test:ci — spec to stdout + Node's built-in junit reporter to
target/surefire-reports/TEST-js-executor.xml
Wired 'yarn test:ci' into the Maven 'test' phase via frontend-maven-plugin,
so 'mvn test -pl=msa/js-executor' produces JUnit XML that TeamCity's
Maven runner auto-discovers under the 'js-executor' suite name.
TEST_FAST.md picks up the same step.
tsconfig excludes test/ from the production pkg bundle.
The args array passed into the sandbox carried the host realm prototype
chain, so a script could reach the host Function constructor via
args.constructor.constructor and execute arbitrary code in the host
process (read files, run shell commands, dump env vars).
Construct args inside the sandbox context using vm.runInContext('[]'),
then populate with string primitives. The resulting array's prototype
chain belongs to the sandbox realm, so constructor traversal cannot
escape. Strings are primitives and safe to cross the realm boundary.
Affects use_sandbox=true path only. The use_sandbox=false path
(invokeFunction) is intentionally left as-is and explicitly marked as
dangerous-by-design — it compiles and runs user-supplied scripts in
the host realm via vm.compileFunction (parsingContext only isolates
parsing, not execution). It remains as a documented performance
trade-off for trusted, non-public clusters; a startup WARN is logged
when script.use_sandbox=false, and an operator-facing yaml comment
sits next to the setting in config/default.yml.
Reported by Hiroki Imai, LAC Co., Ltd.