Flagvent 2025: Day 21
FV25.21 - Santa's Nice List
Difficulty
medium
Categories
web
Description
Santa has spent the whole year adding names from around the world to his Nice List.
In a surprising move, he's publicly releasing what gift each person will receive.
Rumour has it the very best presents were reserved for the first names added to the list.
Author
mobeigi✍️ This challenge was authored by myself!
Solution
Initial investigation
After loading the challenge website, we are prompted to enter our name before we can access Santa’s Nice List:

We enter our name as mobeigi and load the main Santa’s Nice List page:

The website displays a list of names along with the gift each person received. You can scroll down to load more entries via an endless scroll pagination system.
Based on the challenge description, we suspect we need to find out what gift was assigned to person #1, since the rumour suggests the best presents were reserved for the earliest names added to the list.
Fake flags and red herrings
The challenge author (me) included a bunch of fake flags and red herrings. 😏
- The
index.htmlsource contains:<!-- FV25{Pl34s3_f0rg1v3_m3_f0r_4ll_7h3_f4k3_fl4gs} --> - The total number of people on the list is
46 56 32, which in hex maps to the start of the flag format,FV2. - Rick Astley (#465595) makes an appearance to rickroll you.

- Masahiro Hara (#465555), the creator of the QR code, is holding a QR code with the text
申し訳ありませんが、ここには旗がありません, which translates toSorry, there are no flags here.
- 🙈 (#465495), the see no evil monkey, does not see the hidden text
FV25{f4k3_fl4g_bu7_n1c3_f1nd}.
- Miss Lead (#465455) has an audio recording where she claims the flag is
FV25{just-kidding}.
- Rhett Herring (#465395) has a gift that supposedly triggered an exception revealing
FV25{3v3n_s4n74s_c0d3_1s_n0t_bug_fr33}.
app.jscontains an obfuscated JavaScript function_0x0017with the comment//🧌🧌🧌â³ðŸ˜«â³ðŸ¥±above it. When decoded correctly as UTF-8, it becomes//🧌🧌🧌⏳😫⏳🥱, which is a hint that this area is a troll and a waste of time. This function is also responsible for replacing the gifts client-side for the special entries listed above.
These were all distractions and not relevant to solving the main challenge.
Cursor-based pagination with UUIDv7
As we scroll down the page, we can see API calls being made to the /list endpoint. Two query parameters are used: limit and before.
limit is set to 10, and it turns out this is the maximum value. If we try to increase it, the server returns an error:
{
"error":"Invalid limit. Must be between 1 and 10.",
"provided":"100"
}Manually scrolling to the end of the page would be painfully slow and could take hours. On top of that, the site appears to have rate limiting in place, which makes this approach even less practical.
We can inspect a sample response by calling /api/list?limit=10&before=eyJpZCI6IjAxOWI1MmMyLTNkMWItNzQyMS04ZTE3LTM2ODcyN2Q3NDcyMCJ9:
{
"items": [
{
"id": "019b52c1-5260-7b6d-8fd3-0a548cfa4925",
"personName": "田中 あすか",
"gift": "Honda Grom (Mini Moto)"
},
{
"id": "019b52c0-07a6-7737-ade9-6d3437683068",
"personName": "Dr. Gálné Török Anett",
"gift": "Daily Planner or Calendar for Next Year"
},
{
"id": "019b52bf-0d02-7e9d-be2e-a0fe3096eef8",
"personName": "Lynn de Hoogh",
"gift": "Silicone Baking Mat"
},
{
"id": "019b52bd-c64e-7114-9967-3de6b446e9eb",
"personName": "Antonella Melo",
"gift": "Nord Stage 4 88-Key Keyboard"
},
{
"id": "019b52bc-aac2-79c2-b36f-1ca24e8f3a6d",
"personName": "Quý ông Tùng Trần",
"gift": "Jo Malone London Wood Sage & Sea Salt Cologne"
},
{
"id": "019b52bb-953d-799d-b86e-08b708a476d3",
"personName": "Єва Лавренко",
"gift": "Concert Tickets for Favorite Band"
},
{
"id": "019b52b9-f383-7a9a-8b85-cd1319f4ab81",
"personName": "Romana Tamburini",
"gift": "Contact Lens Case Travel Kit"
},
{
"id": "019b52b9-2a5a-7545-badd-c788ded96be9",
"personName": "Vigo van Kusen",
"gift": "Sailing Lesson"
},
{
"id": "019b52b7-fa8a-7f80-932c-402118bfd006",
"personName": "Sig.ra Gabriella Mattarella",
"gift": "Phase One XT Camera System (Entry Config)"
},
{
"id": "019b52b6-d6dc-78b0-9a8e-2ef769943acc",
"personName": "Mr Reece Lord",
"gift": "Paracord Bracelet"
}
],
"nextCursor": "eyJpZCI6IjAxOWI1MmI2LWQ2ZGMtNzhiMC05YThlLTJlZjc2OTk0M2FjYyJ9",
"count": 10,
"hasMore": true,
"totalCount": 465632
}The response includes a nextCursor value. This is the token we need to pass into the next request to fetch the next page of results.
The cursor is Base64-encoded. When decoded, it becomes:
{
"id":"019b52b6-d6dc-78b0-9a8e-2ef769943acc"
}So it looks like the cursor only contains a single field: id.
If we look at the IDs returned in the first page:
"019b52c1-5260-7b6d-8fd3-0a548cfa4925"
"019b52c0-07a6-7737-ade9-6d3437683068"
"019b52bf-0d02-7e9d-be2e-a0fe3096eef8"
"019b52bd-c64e-7114-9967-3de6b446e9eb"
"019b52bc-aac2-79c2-b36f-1ca24e8f3a6d"
"019b52bb-953d-799d-b86e-08b708a476d3"
"019b52b9-f383-7a9a-8b85-cd1319f4ab81"
"019b52b9-2a5a-7545-badd-c788ded96be9"
"019b52b7-fa8a-7f80-932c-402118bfd006"
"019b52b6-d6dc-78b0-9a8e-2ef769943acc"We notice they all share a similar prefix, followed by what looks like random data.
These IDs are UUIDv7 values, which embed a 48-bit Unix epoch timestamp (in milliseconds) in the most significant bits. The remaining bits include the version and variant, plus 74 bits of randomness.
That means we can manipulate the cursor to jump backwards in time and reach the earliest entries much faster. The challenge description mentions Santa has spent the whole year adding names to the list, so we can craft a UUIDv7 using a timestamp near the start of the year. Since the North Pole is uses UTC, we can work directly in UTC when converting the date to an epoch millisecond timestamp, with no time zone offsets to account for.
First, we generate a UUIDv7 for Wednesday, 1 January 2025 03:00:00 UTC (1735700400000) using a tool like uuidv7.org. This yields the UUIDv7 01941fce-4780-715c-9fd7-bd33e9c827c6.
Next, we open the developer console and run:
const id = "01941fce-4780-715c-9fd7-bd33e9c827c6";
const beforeCursor = btoa(JSON.stringify({ id }));
niceListApp.nextCursor = beforeCursor;Here, we manipulate the JavaScript object to set nextCursor to our custom Base64-encoded cursor: eyJpZCI6IjAxOTQxZmNlLTQ3ODAtNzE1Yy05ZmQ3LWJkMzNlOWM4MjdjNiJ9.
This allows us to scroll down the page to trigger automatic loading of subsequent results using our injected cursor. The person numbering will be incorrect, but the name and gift data will still be accurate.
Alternatively, we could send the request manually to: /api/list?limit=10&before=eyJpZCI6IjAxOTQxZmNlLTQ3ODAtNzE1Yy05ZmQ3LWJkMzNlOWM4MjdjNiJ9 and inspect the results directly.
Scrolling down the page reveals the start of Santa’s Nice List, which includes many Flagvent participants. You will appear as the first person on the list based on the name you entered when you first joined the site. If your name was already on the list, it would have been replaced with Ghost.
Thankfully, your gift contains the daily flag!

Flag:
FV25{Pr3d1ct4bl3_P4g1n4t10n_w1th_UUIDv7}Hidden 4
This challenge also contained the solution to: FV25.H4 - Waiting for Christmas