Every relationship starts with good intentions. On October 9, I created my first Facebook account for one reason: to report a security bug to Meta.
Within about two hours, the account was permanently disabled. I did the video selfie verification they asked for. That felt fast for a relationship that was two hours old. My appeal was rejected anyway.
Here is the catch: Meta's bug bounty portal sends you through Facebook to open a report. I can see that my report exists. I just can't open it, answer questions or add evidence.
I don't think anybody did this on purpose. To me it looks like an automated false positive: brand new account, no history, and the only thing it ever did was file a security report.
How it went
- Oct 9: I submit the report and lose the account. I email security@ and bugbounty@. No substantive reply.
- Oct 13: I open a public GitHub issue, without technical details, asking how to reach the team.
- Oct 24: Day 15. I ping the maintainers. One of them answers the same day and asks me to email the details. The report now shows as "Triaged".
- Oct 25: The fix lands in mvfst.
- Oct 26: A Meta engineer confirms by email that the fix came from my report and says the bug bounty team will reach out.
- Nov 3: CERT-Bund, Germany's national CERT, forwards my request to Meta. They take no position on the account or the bounty. So yes, we have reached the stage where a federal agency passes notes between us.
- Nov 5: Still nothing from the bug bounty team.
To be fair, the people who write the code were great. Two engineers on the mvfst team answered a stranger's ping and took it seriously. The ghosting is a process problem, not a people problem.
The bug
mvfst is Meta's open source QUIC implementation. QUIC has a packet called Retry, which arrives before the handshake and carries a 16-byte integrity tag. RFC 9001 says what the tag is for: only someone who has seen the client's Initial packet should be able to send a valid Retry.
mvfst computed that tag correctly. Then it ignored the answer.
// verifyRetryIntegrityTag returns Expected<bool, QuicError> if (!clientConn_->clientHandshakeLayer->verifyRetryIntegrityTag( *originalDstConnId, *retryPacket)) { // drop the packet } With a bad tag, the function returns a successful Expected that contains false. But !expected asks "is there an error?", not "is the value false?". So the drop branch never ran for a bad tag.
The existing unit test made the same mistake. EXPECT_TRUE(verifyRetryIntegrityTag(...)) passes for both true and false.
The result: the client accepted a Retry with any tag, took the attacker's connection ID and token, reset its state and restarted the handshake.
What it actually means
The attacker here is blind and off-path. They have to spoof the server's address, know the client's IP and UDP port, and land one datagram in a short window during connection setup. That is a real hurdle. An attacker who is on the path gains nothing from this bug, because they can compute a valid tag anyway.
I tested it with mvfst's own echo client and server over real UDP on my own machine, using a Retry with an all-zero tag:
- QUIC v1: the connection attempt fails with
TRANSPORT_PARAMETER_ERROR. - mvfst's own version (
0xfaceb002, the client default): the handshake completes with the attacker's connection ID and token, and no error is raised. - With the fix: the Retry is dropped and the connection completes normally.
What I did not do: send this over the internet, test any Meta system, or check current Facebook or Instagram app builds. The attacker does not get the handshake or application keys. My own rating is Medium (CVSS 6.5). Meta's rating? See above, I can't open the report.
The fix
auto integrityResult = clientConn_->clientHandshakeLayer->verifyRetryIntegrityTag( *originalDstConnId, *retryPacket); if (!integrityResult.has_value() || !*integrityResult) { // drop the packet } If you embed the mvfst client, use v2026.10.26.00 or later.
What I took away
-
Expected<bool, E>has two kinds of "no". If you only need yes or no, returnbool. If you only need success or error, returnExpected<void, E>. - A test that never sees bad input doesn't test validation. The bug survived because nothing ever fed the check a wrong tag and looked at the result.
- A social media account should not be the only door to a security report. When automation closes that door, researchers need another way in.
Where we stand
The bug is fixed, and that matters most. Thanks to the mvfst engineers and to CERT-Bund for helping.
I still can't open my report, and I don't know what happens with it next.
Meta, if you're reading this: it's not me, it's your account integrity system. You have my email.

