Files
chimera-gfx-Public/docs/runtime/phase-0.9e-r-port9020-source-audit.md
Chimera GFX release export a6037502d7
phase0-ci / build-and-audit (push) Successful in 2m14s
Publish Chimera GFX source
2026-09-03 03:27:14 +02:00

7.2 KiB
Raw Permalink Blame History

Phase 0.9E-R official Y2JB port audit

Date: 2026-07-18

Port-9020 classification: PORT_9020_REFERENCE_ONLY

Every official tag (Y2JB-1.2.1, 1.3, 1.4, 1.5, 1.6) has exactly two 9020 text references:

  • README.md: a payload_sender.py ... 9020 payload.bin example;
  • payload_sender.py:29: the same usage example.

No tag contains a socket bind, listen, connect target, parser, mapper, ELF loader, or dispatch function fixed to port 9020. Therefore the example cannot be promoted to an implementation.

Actual Remote JS Loader

At release 1.6 commit 0dbbf4e7e0203af7e5d101a3256c634edf4e3ba2, the implementation is download0/cache/splash_screen/aHR0cHM6Ly93d3cueW91dHViZS5jb20vdHY=/remotejsloader.js.

Lines Function / block Contract
28 allocation fixed MAXSIZE = 500 * 1024; one 512000-byte receive buffer
1039 create_socket TCP/IPv4, SO_REUSEADDR, INADDR_ANY, port 0, backlog 3
4147 get_port reads assigned ephemeral port
4988 setup_socket_until_port_50000 creates/closes up to 60000 sockets seeking assigned port 50000; falls back to last port
90105 recreate_socket creates a new ephemeral listener after accept failure
107119 initial setup reports actual IP and port
122209 accept loop infinite accept/read/decode/eval loop
145164 receive loop reads until EOF or 512000 bytes; partial reads accumulate
168188 validation rejects empty/error; 1.6 rejects ELF magic only
190203 dispatch UTF-8 decode, eval, same-connection log writes, close in finally

Protocol properties:

  • server: PS5-side JavaScript listener;
  • expected port: normally 50000, but explicitly dynamic;
  • framing: TCP connection close/EOF;
  • maximum accepted prefix: 512000 bytes;
  • content: JavaScript; 1.6 rejects only 7f 45 4c 46;
  • authentication: none;
  • declared length, version, checksum, or hash: none;
  • timeout: none;
  • full-limit rejection: absent; reaching 512000 bytes can dispatch the prefix without proving EOF;
  • native mapping/entrypoint: absent; received bytes are text-decoded and evaluated;
  • filesystem write: none in this receive function;
  • retry behavior: internal listener allocation/recreation loops exist;
  • crash/hang risk: untrusted JavaScript evaluation, unbounded accept lifetime, blocking reads, and no deadline.

The 1.2.1/1.3 loader uses Git blob 21663be4a0fab6b6a829824946f54706fb1be839; 1.4/1.5 use decb42ba0bbd2bdc8d1568d33b6d772f9fe24d8e; 1.6 uses dd4957530e7a88c889877a7dcb3433642a71e019. Release 1.6 added ELF-magic rejection. Release 1.4 added streaming logs over the accepted connection.

This is a concrete official implementation, but it is not a port-9020 implementation.

Lapse and port 9021

The official chain is:

Remote JS Loader (~50000) → lapse.js → load_aioshellcode → embedded kexp + elfldr bytes → elfldr listener 9021

Relevant source:

  • payloads/lapse.js:1707-1717 requires load_aioshellcode and rejects firmware above 10.01;
  • payloads/lapse.js:1725-1734 creates a per-run lapse.fail marker;
  • payloads/lapse.js:1639 calls load_aioshellcode after exploit setup;
  • aioshellcode.js:12-24 locates embedded files in sandbox slots;
  • aioshellcode.js:26-45 maps the kexp binary with JIT shared executable memory;
  • aioshellcode.js:47-76 starts and joins its thread;
  • aioshellcode.js:78-90 reads the embedded elfldr into process memory;
  • aioshellcode.js:107-117 passes pipe state, allproc, elfldr address, and size to the embedded binary;
  • misc.js:262-302 treats a successful loopback connection to 9021 as a jailbroken/elfldr-running signal;
  • README.md:127-137 tells the host to send an ELF to 9021 after Lapse.

The port-9021 listener itself is contained in an ELF binary. Y2JB contains no generator or listener source for the 1.6 ELF. Release 1.5 embeds the already pinned public elfldr v0.23 asset byte-for-byte; release 1.6 embeds a distinct binary. No 1.6 elfldr source commit is invented.

Safety classification

The Remote JS Loader is independent of an already running elfldr and Payload Manager at source-architecture level, but deployed use is unbound because the local backup is not an official outer asset. It also uses ~50000, not 9020.

Consequently:

  • PORT_9020_IMPLEMENTATION_FOUND: false;
  • PORT_9020_IMPLEMENTATION_PARTIAL: false;
  • PORT_9020_REFERENCE_ONLY: true;
  • Phase 0.9F offline design allowed: false.

Security and robustness findings

Finding Classification Evidence and consequence
Receiver dispatches UTF-8 through eval SESSION_CRASH_RISK arbitrary JavaScript can hang or terminate the current exploit session
No receiver deadline; infinite accept loop SESSION_CRASH_RISK blocked reads and repeated listener lifetime have no bounded cleanup
Buffer limit can dispatch without proven EOF PROTOCOL_INTEGRITY_RISK a 512000-byte prefix can be treated as complete
No length, authentication, checksum, or hash PROTOCOL_INTEGRITY_RISK source does not bind received bytes to an intended request
Sender has no timeout, acknowledgement, response read, or hash PROTOCOL_INTEGRITY_RISK local sendall completion is not peer receipt or execution proof
Lapse creates common_temp/lapse.fail UNKNOWN source proves a filesystem side effect, but deployed persistence and reboot semantics remain unobserved
Lapse/kexp intentionally changes kernel state BRICK_RELEVANT it is outside every authorization in this phase and cannot be treated as read-only
Embedded 1.6 elfldr has no source/generator UNKNOWN listener bounds, parser, mapping, cleanup, and crash behavior cannot be source-audited here
Sender usage errors return implicit success HOST_ONLY automation could misread a local invocation error; no device action occurred

A session crash is not automatically a brick: the reviewed Remote JS receive function does not itself replace a live file or enable autoload. However, the local backup is unbound and the subsequent Lapse path contains explicit kernel and filesystem effects, so no device-risk conclusion or recovery guarantee is promoted from that source architecture.

Firmware selection and reboot boundary

At release 1.6:

  • main.js:681-729 identifies supported YouTube app layouts and labels versions 01.000.003, 01.000.030, and 01.009.202 with minimum firmware 4.03, 12.20, and 13.20 respectively;
  • misc.js:92-108 obtains kern.sdk_version and formats the firmware value;
  • main.js:967-971 assigns and reports that value;
  • payloads/lapse.js:1707-1717 requires load_aioshellcode and rejects versions above 10.01.

Thus 9.60 passes the release-source comparison in Lapse. It does not prove that release 1.6 is deployed, that its masks match the device, or that the runtime chain succeeds.

Listener sockets, JavaScript state, mappings, threads, and loaded code are process- or kernel-resident in source architecture. The Y2JB cache and lapse.fail path are filesystem state. Source alone does not prove which state a reboot removes, whether the original trigger remains usable, or whether a crash permits clean restart. The classification stays REBOOT_RECOVERY_UNPROVEN.