This guide covers the Fastjson 1.2.83 @JSONType resource path and the modern-JDK
Linux continuation that reopens a cached remote JAR through /proc/self/fd/N.
The exact single-body chain has been reproduced with AutoType disabled, a fixed
DTO, normal embedded-Tomcat request threads, JDK 17, and both Spring Boot 2.7 and
3.2 loaders. A normal DTO response does not rule out class initialization.
fjdetect.py is passive: it reads JSON from a file or stdin and makes no network
connections. It decodes JSON before looking for special keys, so Unicode-escaped
forms of @type and its value are covered. It also preserves duplicate object
keys in encounter order; a later benign duplicate cannot erase an earlier
resource probe from the analysis. Per-document walking stops with an explicit
error after 256 levels or 100,000 nodes, and later NDJSON records still run.
# One captured request body
python3 scanner/fjdetect.py request.json
# Structured logs, one JSON record per line. A JSON body stored as a string field
# is decoded recursively.
python3 scanner/fjdetect.py --ndjson gateway.jsonl
# Machine-readable output. Exit 2 means a remote-JAR or FD indicator was found.
python3 scanner/fjdetect.py --json request.jsonSeverity is intentionally evidence-based:
| Severity | Meaning |
|---|---|
CRITICAL |
A failure-soft remote jar:http/jar:https type ending in Exception/Error is followed in the same array by a dense process-FD candidate sequence. |
HIGH |
A remote resource-shaped @type, any remote seed plus an FD candidate, or a dense FD-only sequence consistent with a second request. |
MEDIUM |
An individual jar:file:/proc/{self,thread-self,pid}/fd/N or /dev/fd/N candidate. |
CLEAN |
No indicator for this specific chain. Other Fastjson risks may still exist. |
When a payload uses the public fdN class-naming convention, the detector checks
that /fd/N agrees with that class number. The convention is optional: an
arbitrary candidate class path such as !/x/Payload remains an FD indicator.
Run its regression suite with:
PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s scanner/tests -vInspect the parsed JSON tree, not only raw bytes:
- Recursively collect values whose decoded key is exactly
@type. - Flag remote resource forms beginning with
jar:http:,jar:https:,http:, orhttps:when they use the Fastjson dot-to-slash construction. - Flag any
jar:file:type that addresses/proc/self/fd/N,/proc/thread-self/fd/N,/proc/<pid>/fd/N, or/dev/fd/N, regardless of the class entry following!. - Raise priority when one array contains a remote seed followed by several FD values, especially a consecutive or near-consecutive range.
- Treat a dense FD-only request as a possible second stage: the JAR cache is process-global and may have been seeded by an earlier request.
- Correlate repeated individual FD candidates across requests to the same service/process after a remote seed. The public FearsOff disclosure describes a process-persistent sweep with one candidate number per request.
fjdetect.py evaluates each JSON document independently and intentionally keeps
no cross-record state. Implement the final correlation step in the gateway,
SIEM, or runtime telemetry layer where source, destination, process and time
window are available.
Do not rely on a literal raw-body search for @type. JSON \uXXXX escapes are
decoded before Fastjson handles special keys, duplicate keys can be processed in
encounter order, and a request body may itself be stored as an escaped string
inside a structured log record. A parse/inspection error is not a clean result.
High-value host/network evidence includes:
- two outbound HTTP GETs for the same extensionless JAR resource from one parse;
- creation of
/tmp/jar_cache*.tmp(or the configured JVM temp directory) followed by the Java process retaining an open descriptor to it; - subsequent JAR opens through
/proc/self/fd/Nor/dev/fd/N; - class names or exceptions beginning with
jar:http:orjar:file:/proc/self/fd/; - a parse error or even a normal fixed-DTO response immediately after those events.
Container monitoring can correlate the Java PID's outbound connection, temp-file
creation, and openat/readlink activity on its own FD namespace. The exact FD
number is not stable, so alert on the sequence rather than a hard-coded number.
fjscan_static.py reports EXPOSED only when Fastjson package content,
metadata-verified exact 1.2.83, and actual Boot loader class content occur in
the same inspected composition. POM/filename-only Fastjson versions and
manifest-only Boot launchers remain heuristic REVIEW evidence. Reproduced
Boot 2 and Boot 3 artifacts also receive modern_fd_candidate=true. Versions
1.2.48-1.2.82 contain the underlying resource probe but not the reproduced
1.2.83 single-body failure-soft continuation, so they are REVIEW_PROBE pending a
separate two-request/version test. Nested archives and exploded/thin layouts are
bounded; any limit or inspection error is explicit and forces REVIEW.
fjscan_probe.py's built-in canary deliberately serves an empty HTTP 404 and no
class/JAR. Configure an external collaborator equivalently. A callback proves only
resource lookup and egress (FETCH_REACHABLE), not class definition or RCE.
Redirects are handled explicitly: cross-host destinations are blocked, and a
standard same-host HTTP:80-to-HTTPS:443 upgrade loses every caller-supplied
header except Content-Type, User-Agent, and Accept. HTTPS downgrade and
all other origin or port changes are blocked before contact. External mode cannot query the
collaborator, labels its requests UNVERIFIED_SENT, and exits 0.
Use the marker-only modern-fd/ lab for end-to-end confirmation; do not turn the
fleet scanner into an execution probe.
- Preserve the decoded request, original bytes, process start time, loader/JDK
identity, outbound transcript, temp-file metadata, and
/proc/<pid>/fdlinks. - Isolate the workload and block unnecessary JVM egress.
- Enable Fastjson SafeMode on the ordinary handler-free path and audit any
installed
AutoTypeCheckHandlerbecause handlers run before SafeMode in 1.2.83. - Migrate untrusted parsing away from Fastjson 1.x, preferably to a pinned and regression-tested Fastjson2 release or another maintained parser.
- Treat DTO binding and JDK 9+ as insufficient mitigations for this composition.
Linux is the reproduced FD namespace in this project. /dev/fd is detected as a
macOS-oriented sibling indicator, but the macOS and Windows runtime claims still
require separate OS-specific validation.