TL;DR Link to heading

While analyzing Neverness to Everness’ authentication process, I discovered that authentication data was transmitted in plaintext and could be intercepted and modified by an attacker on the same network as the victim. Additionally, this authentication data lacked replay protection, meaning it could be reused indefinitely.

By combining these vulnerabilities, an attacker could capture another player’s authentication data, replay it from any system, and ultimately authenticate and play NTE as a compromised user at any time.

This post walks through the full exploit chain, outlining my initial discovery to full account takeover. The exploit code is located here on my Github

These vulnerabilities were responsibly disclosed to Perfect World / Hotta Studio. At the time of publication, both vulnerabilities remain unpatched and CVE assignments are pending:

  • CVE Pending: Cleartext Transmission of Sensitive Information (CWE-319)
  • CVE Pending: Insufficient Session Expiration (CWE-613)

Introduction Link to heading

A few months back, my Twitter timeline was full of content from a new game called Neverness to Everness (NTE). It’s an open-world, GTA-like gacha game, and I thought it looked really neat.

Pasted image 20260623181639.png

Modern gacha games are incredibly popular nowadays, and I’ve always found it crazy how quickly these games seem to appear. Games like Arknights: Endfield, Honkai: Star Rail, Wuthering Waves, and many others appear to be enormous money makers. Some players spend hundreds or even thousands of dollars on cosmetics, characters, and other in-game purchases.

Given the pace at which these games are developed and released, I couldn’t help but wonder if some security corners were being cut in the name of development time.

Following this, I installed NTE, created my account, and opened Wireshark. What started as a quick look at the game’s network traffic eventually resulted in two zero-day vulnerabilities being discovered and a full account takeover exploit chain being created!

Unencrypted Authentication (CWE-319) Link to heading

After playing for a few minutes, I closed NTE and started looking through my Wireshark capture. I focused primarily on the authentication process, which takes place over destination port 30031.

Looking at the TCP stream, I noticed some plaintext bits floating around. Some things looked like a UUID, an authentication token, various keys, my public IP address, and more. Scrolling down a bit more, I saw my character name, coordinates, and realized that all of this was unencrypted!

Pasted image 20260623182721.png

Google FlatBuffers Link to heading

After reviewing the authentication stream more closely, I eventually learned that this is using Google FlatBuffers - a lightweight, zero-copy binary serialization format commonly used in game development for its performance in latency-sensitive applications.

My first step was building a decoder script capable of parsing the FlatBuffers data structures used in NTE’s authentication sequence. This would ensure I’m reliably parsing authentication data when I ultimately want to replay or manipulate them in transit.

python3 poc.py decode 1000000000000a000c...

Pasted image 20260622175951.png

With the data structure decoded, here are the fields I found to be relevant:

  • Hardware ID (0x00a4, 0x00d8): An identifier assigned at installation and appears to be for other Hotta/Perfect World games, but doesn’t seem relevant for authentication.
  • Public IP (0x010c): The connecting client’s public IP address.
  • User Secret (0x014c): A UUID-format credential transmitted every time a client logs in. Not rotated between sessions unless the user fully logs out and back in.
  • User ID (0x0178): A unique numeric identifier used specifically for authentication, separate from the “friend code” used for adding people in-game.

There are some other fields I don’t entirely understand, but they didn’t appear to be necessary for authentication.

With the data structure decoded and plaintext transmission confirmed, I moved on to abusing the authentication process, specifically targeting the User Secret and User ID.

ARP Poisoning Link to heading

My first approach was a man-in-the-middle attack via ARP spoofing. By poisoning the ARP cache of machines on my local network, I can sit between victims and their gateway and passively capture authentication data as they log in. For this proof of concept, I focused on a single target host:

python3 poc.py mitm -i eth0 -t 10.0.1.17 -g 10.0.1.1

After logging into NTE on my victim machine, the authentication data is successfully captured and decoded:

Pasted image 20260624180831.png

Pasted image 20260623204030.png

The attack surface here is any victim on the same LAN as the attacker. Think a LAN party, a university network, or a computer café. The latter felt specifically relevant, as computer cafés are fairly popular in Asia, where a large portion of gacha players are based out of.

Replay Attack (CWE-613) Link to heading

Capturing a victim’s authentication data is only useful if it can actually be replayed! Looking back at the Wireshark capture, the client starts every login sequence by sending a fixed 4-byte length prefix:

98010000

Since this is the same in every authentication flow I’ve captured, I’ll just call it the “magic bytes.” Once the server receives them, it responds with FlatBuffers data like this:

Pasted image 20260622184546.png

After the server responds, I can send my captured data to the server:

python3 poc.py auth 1000000000000a000c...

Pasted image 20260624181138.png

Pasted image 20260623204145.png

If successful, the game server responds with another FlatBuffers structure that contains a session token!

Pasted image 20260624181303.png

Alongside that session token, the server sends additional FlatBuffers data containing the game server, active character, current coordinates, and more:

Pasted image 20260624181340.png

The fact this was successful indicates client authentication data does not have any form of replay protection. I can send the same FlatBuffers data multiple times, over multiple days, and from any IP address. Once a victim’s authentication data is captured, it can be replayed indefinitely.

Session Injection Link to heading

With the man-in-the-middle and replay attack working, I wanted to complete the exploit chain by attempting to play the game as a compromised victim.

NTE ships with an anticheat system, which prevents any attempt to inspect the game’s active memory or accessed files. I looked into the game’s local configuration files, which contain some encrypted data (with a known key), but couldn’t find anything useful to modify there either.

After thinking about it more, I realized that since I can sit in the middle of my own authentication process, I can capture my own FlatBuffers data, patch in a victim’s User ID and User Secret, and forward the modified data to the game server. The Hardware ID and other client-specific fields didn’t result in any server rejection during testing, so this should work!

I first logged in as my own account without anything running to confirm I’m playing as Mint:

Pasted image 20260624183711.png

After logging out, I started the proxy and injected a compromised User ID and User Secret into the intercepted authentication data coming from my machine:

python3 poc.py proxy -i eth0 -t 10.0.1.17 -g 10.0.1.1 0x0178=COMPROMISED-USER-ID 0x014c=COMPROMISED-USER-SECRET

Pasted image 20260623205058.png

Looking back at NTE, I can confirm the account hijack via injection was successful:

Pasted image 20260624183616.png

With that, the full account takeover exploit chain is complete!!

Disclosure Timeline Link to heading

After completing the exploit chain, I immediately reached out to Perfect World/Hotta Studio to disclose the vulnerabilities found. Industry-standard responsible disclosure timelines, such as Google Project Zero’s 90-day policy, typically allow vendors 90 days to remediate before public disclosure. At the time of publication, over 170 days have passed since the initial report.

The following outlines the disclosure timeline:

  • May 8th, 2026 - Reached out to [email protected] to confirm appropriate disclosure channel
  • May 8th, 2026 - NTE responded with general helpdesk and support information
  • May 8th, 2026 - Submitted full vulnerability overview, proof-of-concept code, and video demonstrations
  • May 8th, 2026 - NTE acknowledged and thanked for the disclosure
  • May 16th, 2026 - Provided update with additional findings
  • May 18th, 2026 - NTE confirmed the team was working on a fix
  • June 17th, 2026 - Followed up on patch status, vulnerabilities remained unpatched after roughly a month
  • June 17th, 2026 - NTE acknowledged and assured fixes were still in progress
  • June 18th, 2026 - Self-submitted two CVE requests to MITRE
  • October 4th, 2026 - Followed up noting vulnerabilities were still present, asked about avenues for pursuing CVEs
  • October 6th, 2026 - NTE acknowledged and thanked for the follow-up
  • October 9th, 2026 - NTE stated information was shared with the appropriate team, closed ticket
  • October 13th, 2026 - Notified NTE of intent to publicly disclose findings on October 27th, 2026
  • October 14th, 2026 - NTE acknowledged the request
  • October 15th, 2026 - NTE thanked for the disclosure, noted the disclosure date, pending CVE submissions, and stated information had been shared with relevant teams
  • October 27th, 2026 - Published PoC and blog post

Conclusion Link to heading

With that, I’ve successfully discovered two zero-day vulnerabilities in Neverness to Everness. The following CVE requests have been submitted to MITRE and are pending assignment:

  • CVE Pending: Cleartext Transmission of Sensitive Information (CWE-319)
  • CVE Pending: Insufficient Session Expiration (CWE-613)

This was a ton of fun, was a tremendous learning opportunity, and was extremely rewarding. The proof-of-concept tooling has been uploaded to my GitHub.

More fun research and CVEs to come! :)

References Link to heading