[BUG] `ArrayIndexOutOfBoundsException` on a field name ending in a backslash — `JSON.parse("{\"\\")`
- Dominant language
- Java
- Stars
- 4.4k
- Forks
- 613
- Avg merge
- 1d 22h
- Merged PRs (30d)
- 6
Description
**Version:** 2.0.64 (reproduced against the published jar)
**Class:** `com.alibaba.fastjson2.JSONReaderASCII`
**Related:** #7790 — same trigger, different reader and method (see below)
A three-byte input throws `ArrayIndexOutOfBoundsException` instead of `JSONException`:
```java
JSON.parse("{\"\\"); // the three bytes: { " \
```
```
java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
at com.alibaba.fastjson2.JSONReaderASCII.readFieldName(JSONReaderASCII.java:949)
at com.alibaba.fastjson2.JSONReader.read(JSONReader.java:3243)
at com.alibaba.fastjson2.JSON.parse(JSON.java:138)
```
It is specific to a backslash ending a **field name**:
| input | result |
|---|---|
| `{"\` | **AIOOBE** |
| `{"a\` | **AIOOBE** |
| `{"a":1,"b\` | **AIOOBE** |
| `{"a":"\` | `JSONException` — escape in a value, different path |
| `[{"\` | `JSONException` — array path uses `readFieldNameHashCode()` |
As with the other cases of this kind, callers following the documented contract do not
catch it:
```java
try { JSON.parse(untrusted); } catch (JSONException e) { /* reject */ }
```
## Cause
`JSONReaderASCII.readFieldName()`, lines 945-952:
```java
for (int i = 0; offset < end; ++i) { // guard: offset < end
int c = bytes[offset];
if (c == '\\') {
nameEscape = true;
c = bytes[offset + 1]; // line 949 -- reads offset + 1
offset += (c == 'u' ? 6 : (c == 'x' ? 4 : 2));
continue;
}
```
The loop condition covers `bytes[offset]`, but line 949 looks **one ahead** to decide the
skip distance. With the backslash as the final byte, `offset + 1 == end`.
Note this differs from the other reports of this class: it is not a missing
`offset == end` check before a `bytes[offset++]`, it is a lookahead the existing guard
does not cover.
## Fix
```diff
--- a/core/src/main/java/com/alibaba/fastjson2/JSONReaderASCII.java
+++ b/core/src/main/java/com/alibaba/fastjson2/JSONReaderASCII.java
@@ -946,6 +946,11 @@
int c = bytes[offset];
if (c == '\\') {
nameEscape = true;
+ // The loop condition only guarantees offset < end; this reads one past the
+ // cursor, so a backslash as the final byte would run off the array.
+ if (offset + 1 >= end) {
+ throw new JSONException(info("illegal input"));
+ }
c = bytes[offset + 1];
offset += (c == 'u' ? 6 : (c == 'x' ? 4 : 2));
continue;
```
Throwing is appropriate here — a name ending in a backslash cannot be completed, and
`JSONException` is what the surrounding code already raises for malformed names.
Verified against 2.0.64: `{"\`, `{"a\` and `{"a":1,"b\` now raise `JSONException`, and
escaped field names are unaffected — `{"a\"b":1}`, `{"a\\b":1}`, `{"aAb":1}`,
`{"a\tb":1}`, `{"a":1}`, `{}`, `{"a":"x\"y"}` all parse exactly as before.
## Relationship to #7790
#7790 reports the same trigger — a lone trailing backslash — in
`JSONReaderUTF16.readString()` at line 3287. This is the field-name equivalent in the
ASCII reader:
| | #7790 | this issue |
|---|---|---|
| reader | `JSONReaderUTF16` | `JSONReaderASCII` |
| method | `readString()` | `readFieldName()` |
| position | string value | field name |
| minimal | `"\` (needs a UTF16-backed String) | `{"\` |
Both reproduce on 2.0.64, and neither fix affects the other.
## Not a security issue
The out-of-range access is a read, and the JVM bounds check stops it — no memory is read
or disclosed, and the exception message contains only the input length. The practical
impact is an unchecked exception escaping a caller's `catch (JSONException)`.
---
Found by the CISPA Fandango Team
Contributor guide
Research direction
Start in core/src/main/java/com/alibaba/fastjson2/JSONReaderASCII.java at readFieldName(), reached through JSON.parse(). Reproduce the trailing-backslash inputs such as {"\\ and confirm they raise JSONException rather than ArrayIndexOutOfBoundsException; verify that the listed escaped field-name and value cases still parse normally.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 84/100