7.2 KiB
Phase 0.9E-R official Y2JB port audit
Date: 2026-07-18
Port-9020 classification: PORT_9020_REFERENCE_ONLY
Exact 9020 search
Every official tag (Y2JB-1.2.1, 1.3, 1.4, 1.5, 1.6) has exactly two
9020 text references:
README.md: apayload_sender.py ... 9020 payload.binexample;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 |
|---|---|---|
| 2–8 | allocation | fixed MAXSIZE = 500 * 1024; one 512000-byte receive buffer |
| 10–39 | create_socket |
TCP/IPv4, SO_REUSEADDR, INADDR_ANY, port 0, backlog 3 |
| 41–47 | get_port |
reads assigned ephemeral port |
| 49–88 | setup_socket_until_port_50000 |
creates/closes up to 60000 sockets seeking assigned port 50000; falls back to last port |
| 90–105 | recreate_socket |
creates a new ephemeral listener after accept failure |
| 107–119 | initial setup | reports actual IP and port |
| 122–209 | accept loop | infinite accept/read/decode/eval loop |
| 145–164 | receive loop | reads until EOF or 512000 bytes; partial reads accumulate |
| 168–188 | validation | rejects empty/error; 1.6 rejects ELF magic only |
| 190–203 | 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-1717requiresload_aioshellcodeand rejects firmware above 10.01;payloads/lapse.js:1725-1734creates a per-runlapse.failmarker;payloads/lapse.js:1639callsload_aioshellcodeafter exploit setup;aioshellcode.js:12-24locates embedded files in sandbox slots;aioshellcode.js:26-45maps the kexp binary with JIT shared executable memory;aioshellcode.js:47-76starts and joins its thread;aioshellcode.js:78-90reads the embedded elfldr into process memory;aioshellcode.js:107-117passes pipe state,allproc, elfldr address, and size to the embedded binary;misc.js:262-302treats a successful loopback connection to 9021 as a jailbroken/elfldr-running signal;README.md:127-137tells 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-729identifies supported YouTube app layouts and labels versions01.000.003,01.000.030, and01.009.202with minimum firmware 4.03, 12.20, and 13.20 respectively;misc.js:92-108obtainskern.sdk_versionand formats the firmware value;main.js:967-971assigns and reports that value;payloads/lapse.js:1707-1717requiresload_aioshellcodeand 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.