Four pieces of a birthday cake were scattered across Spotify, Instagram, Reddit, and GitHub. We finally put them together—and every ordinary QR scanner still saw nothing. The breakthrough came when we stopped asking a detector to recognize a photograph and started sampling the structure of a QR code ourselves.
That solve captures what made Cryptic Finds memorable: the right clue often looked like the wrong kind of evidence. A JPEG was hexadecimal text; a silent recording carried pulses; an image viewer quietly ignored a second photograph appended to the first.
This is a detailed account of our recorded investigation, including the detours that changed our approach. The challenge board reached 22 of 43 cases closed and 3,100 points. We preserved 20 accepted flags; the missing solves and unfinished Case 23 remain clearly marked.
Spoilers ahead: this post includes accepted flags, extraction methods, and public puzzle-account links. It is based on the supplied post-competition records, rather than a new verification of the live challenge site. Cryptic Finds and its challenge artwork are credited to their organizers and creators; board screenshots credit ACM Manipal. AI assistance supported the research and scripts described here.
What this write-up covers
Cryptic Finds was a story-driven CTF hosted at crypticfinds.xyz. The investigation followed a narrator trying to understand their mother's research and death. Individual case files mixed cryptography, file forensics, audio analysis, visual puzzles, and open-source research.
The last website state we verified was:
| Item | Last verified state |
|---|---|
| Cases closed | 22 of 43 |
| Easy board | 13 of 13 |
| Medium board | 9 of 22 |
| Hard board | 0 of 8 |
| Points | 3,100 |
| Accepted flags preserved in our notes | 20 |
| Cases closed without a recorded solve in this session | 1 and 16 |
| Last investigated case | 23, unresolved |
The 20 preserved flags correspond to Cases 2–15 and 17–22. Case 1 was already solved when this investigation began. Case 16 appeared solved when the session resumed, but its answer and method were not captured. Neither missing walkthrough is reconstructed here.
This is a record of the last verified state, not the final competition standings or necessarily the account's current progress.

The preserved board state: Cases 20–22 closed, with Case 23 still open.
We began Cryptic Finds with one case already closed and a simple rule: every answer had to become a cryptic{...} flag. The challenges soon became less about recognizing a cipher and more about deciding what kind of evidence we were looking at. A JPEG could actually be hexadecimal text. An apparently silent recording could carry Morse code. A birthday cake assembled from four websites could conceal a QR code that ordinary scanners could not recognize.
The most useful habit was to keep the entire chain of evidence: the original artifact, the transformation, the recovered message, and the website's verdict. That mattered because several challenges used formatting exceptions, and a plausible interpretation was not always the accepted answer.
Flag rules, exceptions, and verification
The general format was:
cryptic{answer_with_underscores}Only the text inside the braces was converted with the organizer's substitution key:
| Letter | Replacement |
|---|---|
| A | 4 |
| B | 8 |
| E | 3 |
| I | 1 |
| O | 0 |
| S | 5 |
| T | 7 |
For example, cached info becomes cryptic{c4ch3d_1nf0}. The prefix cryptic stays unchanged. Underscores represented spaces in the examples; some accepted answers also contained decimal points.
The website's Protocols page explicitly stated that flags were checked case-insensitively and that underscores were supported. This later ruled out capitalization as an explanation for Case 23's rejections.
There were important case-specific exceptions. We preserve the exact accepted strings rather than silently rewriting them to match the general rule:
- Case 5 accepted a partially converted recovered string.
- Case 6 accepted the ordinary venue name.
- Case 8 accepted its recovered message with partial substitutions.
- Case 12 accepted the literal railway station code
MAO, whileM40variants were rejected. - Case 17 explicitly requested lowercase letters, so
flavoringremained alphabetic. - Case 20 instructed us to paste the recovered content exactly, including its existing substitutions.
A website verdict was the final check. Recovering readable text was an intermediate result; a case was called solved only after the board showed it closed or the site displayed a successful verification.
The published lockout rule was five wrong flags within one minute: a one-minute lockout for Medium and two minutes for Hard. A better solving process should reduce speculative submissions, respect those limits, and never treat refreshing as a way to evade them.
Our investigation workflow
We used browser automation to read case files, follow public puzzle profiles, download supplied evidence, and submit recovered flags. Local scripts handled analysis that would be tedious or unreliable by eye.
The main tools and techniques were:
- Python with Pillow and NumPy for images, metadata, bit planes, and binary inspection.
- OpenCV and ZXing C++ for visual-code experiments and the final cake QR recovery.
- SciPy and audio plotting for low-frequency pulses and spectrograms.
- PDF metadata and image extraction.
- Small scripts for hexadecimal, Base64, ROT13, Vigenère, Morse, and book ciphers.
- Public museum catalogues, official site descriptions, railway information, and puzzle-controlled social accounts for OSINT.
We kept downloaded evidence separate from derived images. This was essential for the cake, where social platforms had resized and recompressed different fragments.
The general sequence that worked best was:
- Read the question and its requested answer fields.
- Download the original artifact where available.
- Inspect its real file type, metadata, boundaries, and trailing bytes.
- Apply the transformation supported by the evidence.
- Follow the recovered identifier or instruction within the case's scope.
- Format the requested answer, accounting for explicit exceptions.
- Submit and save the actual verdict.
Easy cases
Case 1 — Already solved before our recorded investigation
Status: closed on the board; no preserved flag or method.
We started with Case 1 already solved. The original solve was not preserved, so this is a gap in the record rather than a reconstructed walkthrough.
Case 2 — The Vampire's Obol
Technique: exact visual identification and museum-catalogue research.
The supplied image showed both sides of a dark coin: an imperial portrait on one side and a cross standing on steps inside a wreath on the other. Identifying the broad coin type was useful, but the requested answer depended on finding the specific museum record.
We matched the artifact to the British Museum's coin registration B.7273, attributed to Tiberius II Constantine, minted in Ravenna, dated 578–582. The notes record a match not just in the main design, but also in the irregular outline and damage to the coin blank. Those details distinguish an exact image match from a merely similar coin.
The catalogue reference was B.7273. Applying B→8 produced:
cryptic{8.7273}Result: accepted, +100 points.
Source: British Museum, registration B.7273.
Lesson: when the answer is an accession or registration number, stop at the exact object record rather than substituting the emperor's name or a general coin classification.
Case 3 — Blood Remembers
Technique: hexadecimal decoding followed by Vigenère decryption.
The monitor text supplied a first layer. Decoding its hexadecimal characters revealed:
BLOOD IS THE KEYThat was an explicit key clue. We then used BLOOD to Vigenère-decrypt:
TLBUXJD_AOFITBO_3The recovered plaintext was:
SANGUIS_MACHINA_3With the required letter-to-digit replacements, the accepted flag was:
cryptic{54NGU15_M4CH1N4_3}Result: accepted, +100 points.
Lesson: the first decoded message can be an instruction for a second cipher. A meaningful phrase such as “is the key” is stronger evidence than guessing common passwords.
Case 4 — Hexed
Technique: hexadecimal decoding and searching a repetitive text corpus.
The file was hexadecimal text with whitespace. Removing whitespace and decoding it produced a large repeated body: 4,999 copies of SANGUIS_IN_MACHINA and one unusual flag-like string.
The embedded string was:
cryptic{d0_n0t_tru5t_th3_v01c3s}This was not yet fully converted according to the event key. The remaining matching letters still needed substitution, including T→7 and S→5. The accepted result was:
cryptic{d0_n07_7ru57_7h3_v01c35}Result: accepted, +100 points.
Lesson: readable flag syntax does not always mean a string is ready to submit. Here the general conversion rule was a final transformation.
Case 5 — The Unsent Draft
Technique: ROT13.
We applied ROT13 to recovered_note.txt. The decoded last line supplied a complete flag. Unlike Case 4, the literal partially converted string was what the validator accepted:
cryptic{1_4m_th3_v3ss3l_n0w}A fully substituted variant was rejected in the recorded attempt.
Result: accepted.
Lesson: preserve recovered output before normalizing it. This case is evidence of an exception, not a reason to ignore the general rules everywhere else.
Case 6 — The Admins Symphony
Technique: binary information encoded in musical notation, followed by geolocation.
The music image used two note heights as a binary alphabet. Our script located note marks along the relevant rows, sorted them left to right, assigned the higher position 1 and the lower position 0, and grouped the resulting stream into eight-bit ASCII characters.
The decoded text was:
wipe.fact.movesThree dot-separated words suggested a what3words address. The recorded location was approximately 40.722254, -73.987066, facing Katz's Delicatessen in New York. Street View was used to confirm the venue rather than relying only on a nearby map label.
The accepted flag was the literal venue name:
cryptic{katzs_delicatessen}Result: accepted.
Lesson: a decoded string may be a location identifier in another system. Recognizing the structure of the output was the bridge from binary decoding to OSINT.
Case 7 — The Sedation
Technique: file-type inspection and historical object identification.
Despite its name, MRI_SCAN_CORRUPTED.jpg was not an ordinary JPEG. Its contents were ASCII text containing hexadecimal values separated by Z characters.
Interpreting the actual bytes rather than trying to repair an MRI image exposed references to a moth and the Harvard Mark II. These pointed to the famous logbook entry documenting a physical insect in the computer's relay mechanism.
The Smithsonian's record confirmed the historical object. The accepted flag was:
cryptic{m07h_h4rv4rd_m4rk_11}Result: accepted.
The preserved flag uses 11 where the historical machine name uses Roman II; the exact accepted string is preserved here.
Source: Smithsonian, “Log Book With Computer Bug”.
Lesson: file extensions are labels, not proof of format. Checking the bytes early can save an entire branch of unnecessary image analysis.
Case 8 — Synesthesia
Technique: low-frequency signal extraction and Morse decoding.
silence.wav seemed uninformative when treated as ordinary audible content. Its useful information was in very low-frequency or DC-like pulses.
The successful approach was to low-pass the signal to approximately 50 Hz, then threshold the resulting waveform at 10,000 in the saved analysis representation. Runs above the threshold represented pulses; short and long pulses mapped to Morse dots and dashes. Longer gaps separated characters.
The preserved decoder used run lengths below 10 as dots, longer active runs as dashes, and inactive runs above 30 as character breaks. Those numbers are specific to the saved processed data, not universal Morse thresholds for arbitrary WAV files.
The decoded message was:
1T_L1ST3NS_THR0UGH_TH3_W1R3SThe literal lowercase form was accepted:
cryptic{1t_l1st3ns_thr0ugh_th3_w1r3s}A fully substituted alternative was rejected.
Result: accepted.
Lesson: silence to human hearing does not imply a flat digital signal. Plotting and filtering can reveal information that listening misses.
Case 9 — The Living Tool
Technique: interpreting a poem and resolving museum identifiers.
The poem described Deep Blue and its chess match against Garry Kasparov. The next task was more specific than naming the computer: we needed catalogue identifiers from two institutions.
The accepted pair was:
| Institution | Recorded identifier |
|---|---|
| Smithsonian | 2002.0251.01 |
| Computer History Museum | 102738727 |
The CHM identifier belonged to the relevant Deep Blue II still-image catalogue record. An older accession candidate, L062302016, was rejected. It is important to distinguish a museum accession number, a catalogue record ID, and the physical object's identity, even when they all refer to Deep Blue.
cryptic{2002.0251.01_102738727}Result: accepted.
Sources: Smithsonian Deep Blue record, Computer History Museum catalogue 102738727.
Lesson: exact field names matter in catalogue challenges. The correct institution and artifact can still yield the wrong answer if the wrong identifier field is copied.
Case 10 — Withdrawn Paper
Technique: PDF metadata and geolocation.
The important clues were stored in the PDF's metadata rather than only in its visible page text:
| Metadata field | Recovered content | Interpretation |
|---|---|---|
| Subject | 44.1117,-68.9094 | Coordinates identifying Browns Head Lighthouse |
| Keywords | dmVzc2Vs | Base64 for vessel |
Combining the place and keyword produced:
cryptic{8r0wn5h34dl1gh7h0u53_v3553l}Result: accepted.
Sources: American Lighthouse Foundation, Browns Head Lighthouse, U.S. Lighthouse Society archive.
Lesson: visible document content, document metadata, and embedded resources are separate evidence surfaces. Check all three before assuming the page itself contains the whole puzzle.
Case 11 — Paper Found
Technique: ROT47, location research, a multi-platform image hunt, QR reconstruction, and barcode decoding.
This was the longest and most instructive solve. The final chain was straightforward in hindsight, but several plausible interpretations diverted us along the way.
Step 1: Decode the paper
The handout, paper found.txt, contained:
cg]aach`ef[ h]dhdgbbbROT47 recovered:
48.2249167, 9.5958333These coordinates led to Obermarchtal, Germany, and the historic military cemetery nearby. The grave trail identified Norbert Iaeger, which matched the puzzle account:
norbert_iaegerThe old spelling “Iaeger” mattered: substituting a modernized spelling without checking could lead to unrelated people.
Step 2: Follow the social trail
The profile trail led across several platforms:
Coordinates → cemetery/grave → Reddit norbert_iaeger
↓
Instagram pseudorama17
↓
Spotify profile
Additional fragment: GitHub pseudorama17-sketch/xyz_1234I found the fourth fragment on GitHub and brought it into the reconstruction. This was a collaborative solve: I contributed hints, corrected interpretations, and supplied evidence, while AI-assisted browser research and local scripts helped with extraction and testing.
Step 3: Assemble four fragments
The cake arrangement was:
| Position | Source |
|---|---|
| Upper left | Spotify party playlist cover |
| Upper right | Cake panel inside an Instagram birthday collage |
| Lower left | Reddit birthday image |
| Lower right | GitHub 133949722284297486.jpg |
We assembled a 1152×1152 image with four 576×576 quadrants. No rotation was needed.
The source quality differed:
- Reddit supplied a native 576×576 PNG.
- GitHub supplied a 576×576 JPEG.
- Spotify supplied only a 300×300 WEBP cover, which had to be resized.
- Instagram supplied a 1080×1439 collage containing the required upper-right panel.
The earlier Instagram crop was (434,756,1010,1332). The cleaned reconstruction used (435,757,1010,1332), a 575×575 crop resized to 576×576, to remove white collage-frame contamination.
Important qualification: this was a geometrically aligned reconstruction, not proof that the original full image's pixels had been recovered exactly. Resizing and social-media compression had already changed some sources. No AI inpainting or invented image content was used.

Four platform fragments aligned into a 1152 × 1152 cake image. Social-media resizing means this is a geometric reconstruction, not an exact recovery of the original pixels.
Step 4: Recognize why ordinary QR scanning failed
Moderator hints emphasized building the image properly and using a familiar everyday tool to extract visual information. We explored phone-camera/QR-scanner and visual-search interpretations, but standard scanners initially found nothing.
The failed routes included:
- Direct ZXing and OpenCV QR scans.
- Hundreds of threshold, blur, scale, and channel variants.
- WeChat QR detection.
- Bit-plane, frequency, and metadata checks.
- Google Lens and Bing Visual Search, which produced generic cake matches or no exact match.
- Grave dates, Reddit Cake Day interpretations, and birthday-related flag guesses.
These failures did not prove that no QR existed. The eventual issue was that its positioning structures were disguised or degraded enough to defeat ordinary detection.
Step 5: Sample the QR module grid
The successful parameter set was preserved by the search script:
| Parameter | Value |
|---|---|
| QR version | 4 |
| Module count | 33×33 |
| Sampled square | 928×928 pixels |
| Square center | (576,576) |
| Top-left coordinate | (112,112) |
| Threshold | Otsu |
| Inverted | No |
QR version 4 has 17 + 4×4 = 33 modules per side. We sampled the center of each module, thresholded those samples into black and white, and restored the standard three finder patterns, their separators, and the timing pattern. We retained the sampled payload and format modules rather than replacing them with a guessed message.
A quiet border was added and the tiny grid enlarged with nearest-neighbor scaling. ZXing's pure QR mode then decoded it successfully.

The sampled 33 × 33 QR grid after restoring standard positioning structures and adding a quiet border.
This repair was justified because the replaced structures are standard QR positioning information. It did not manufacture the link; the decoder still had to recover a valid message from the sampled data.
Step 6: Follow the QR and decode the barcode
The QR yielded a Proton Drive link:
The decoded text contained a trailing space, which was trimmed before opening the URL. The linked barcode_file.pdf contained a Code 128 barcode. Its value was:
4771CThat reads as ATTIC in the event's substitution style, fitting the original attic narrative.
cryptic{4771C}Result: accepted, +100 points; Case 12 unlocked.

The Code 128 barcode extracted from the PDF reached through the recovered QR link.

The board confirms Paper Found closed for 100 points and unlocks INTERCEPT-K.
What we learned from the detours
The real grave research was useful for finding the account, but its dates were not the final answer. The verified Reddit creation date was also not the solution. A screenshot showing an unassociated “Joined Reddit” badge should never have been treated as evidence about the target account.
The important distinction here is between failing to detect a visual code and demonstrating that a code is absent. Once direct scanners stopped providing new information, modeling the expected QR geometry was more productive than continuing generic scans.
Puzzle sources: Reddit profile, Reddit birthday post, Instagram profile, Spotify party playlist, GitHub fragment repository.
Case 12 — INTERCEPT-K
Technique: social-profile discovery, caption acrostics, video observation, and railway research.
The displayed profile name K_loves_Life_Loves_K was not its actual handle. Searching the display name in Instagram led to:
k_finds_her_waysReading caption initials in chronological order spelled:
VANDEBHARATA profile highlight showed a Subway Surfers screen containing 20646, which pointed to train 20646, the Mangaluru Central–Madgaon Vande Bharat.
The destination station code was MAO, and the arrival time used by the accepted answer was 14:10. Our notes identify that as the relevant monsoon schedule. Older or different-season results gave 13:15 and 13:10, which made this a time-sensitive lookup rather than a stable trivia question.
The accepted flag was:
cryptic{MAO_1410}Result: accepted; Case 13 unlocked.
General-rule variants with M40 were rejected. This is a literal station-code exception. The 14:10 time is the one used in the recorded solve, rather than a claim about the permanent timetable.
Puzzle source: Instagram k_finds_her_ways.
Lesson: order social posts by the chronology required by the clue; displayed grid order can be misleading. For operational data such as timetables, retain the season and date context.
Case 13 — CATCH
Technique: historical-operation research and distinguishing similarly described vehicles.
The clues pointed to Veerappan and Operation Cocoon. An ivory-tusk image supported the poaching context, but the final answer depended on identifying the correct vehicle in the ambush account.
The Sweet Box was the sugarcane lorry carrying the technical surveillance team. The Mobile Bunker was a different armed vehicle. Both belonged to the same operation, so recognizing the operation alone was insufficient.
cryptic{5w337_80x}Result: accepted, +100 points. The Easy board reached 13/13, and Medium unlocked.
Sources: K. Vijay Kumar's Veerappan: Chasing the Brigand, chapter 34, page 232 in the referenced copy; supporting Times of India report.
Lesson: when a source names several objects in the same operation, match the object's function to the question before copying its nickname.
Medium cases
Case 14 — Look Inside
Technique: visual least-significant-bit extraction, a positional acrostic, and organization research.
Viewing the image's RGB least-significant-bit layer exposed a poem titled The Midnight Verse. This was a visual message in a bit plane, not simply a plaintext string found by scanning bytes.
The lines began with words including:
Dark
Scarecrows
Embers
Screams
Ghosts
Bats
Wicked
CryptsTaking the second letter of each opening word gave:
A C M C H A I RThe result was a pointer to the ACM chair, not the final flag itself.

The Midnight Verse exposed in the RGB least-significant-bit layer.
We checked ACM Manipal's board information. Different years produced different plausible names: Morvin Prajapati for 2024, Subham Chakraborty for 2025, and Vishal Kumar for the 2026–27 board shown in the supplied Instagram evidence.
The Instagram caption said the group really liked “chairs” and “upper halves.” We interpreted the latter as an instruction to use the first part of the chairperson's name. The accepted answer was Vishal, not a full-name variant:
cryptic{v15h4l}Result: accepted, +200 points.
We tried too many full-name and spelling variants before resolving the first-name instruction. Those attempts are a process lesson, not a shortcut to recommend. Fix the extraction rule before multiplying submissions.
Sources: ACM Manipal team page, ACM Manipal Instagram, and the supplied board screenshots. The accepted website verdict supports the final first-name choice; the “upper halves” reading remains our interpretation of the clue.
Case 15 — Dead Air
Technique: an audio spectrogram, a Gutenberg book cipher, Vigenère, and manuscript research.
This case combined several independent evidence types into a three-part answer.
Stage 1: Frequency and hidden book number
The supplied audio was named 4625kHz.wav. That supplied the first answer component, 4625.
The recording lasted approximately 40.99 seconds, with mono 44.1 kHz, 16-bit samples. A spectrogram revealed 811 after approximately the 29-second mark. That number pointed to Project Gutenberg ebook 811, Doctor Faustus.
Stage 2: Decode the notebook indices
The notebook supplied these one-based word indices:
10407 7568 5746 10369 6314
656 3651 9548 970 3396
3064 11032 2045 10102 1099
2245 2081 629 1168 1320Book ciphers are sensitive to the exact text and preprocessing. Our successful procedure was:
- Use the saved Gutenberg 811 plaintext.
- Remove the Gutenberg opening wrapper through its
*** START OF ... ***marker. - Remove numeric footnote markers matching
[digits]. - Split the remaining text on whitespace.
- Treat the notebook indices as one-based.
- Take the first alphabetic character of each selected word.
The resulting ciphertext was:
ACCBPETJIVTJWCHMIDPWVigenère decryption with the music-related key POORPLACES recovered:
LOOKATTHEDEVILSBIBLEThe key was connected to the Wilco/numbers-station audio lead. The preserved record does not include a full speech transcript, so the key connection can be reported without reconstructing an exact spoken quotation.
Stage 3: Find the Devil's Bible folio
“The Devil's Bible” refers to Codex Gigas. The full-page Devil illustration is on folio 290r, supported by the National Library of Sweden's manuscript record.
The requested numeric component was 290, rather than the entire 290r folio label. Combining the three parts produced:
cryptic{4625_811_290}Result: accepted, +200 points; Case 16 unlocked.
Sources: Project Gutenberg, Doctor Faustus, National Library of Sweden, Codex Gigas.
Lesson: record preprocessing as part of the solution. “Use a book cipher” is not reproducible unless the edition, indexing convention, and treatment of headers and footnotes are specified.

Dead Air closed after the audio, book-cipher, and manuscript clues were combined.
Case 16 — The Unsent Confession
Status: closed on the board when the session resumed; accepted flag and method unknown.
We did not preserve the solve. The board state establishes that the case was closed, but it does not establish the accepted flag or the method. This remains an explicit gap in the walkthrough.
Case 17 — Mise en Place
Technique: an acrostic, data appended to a PNG, indexed selection, and a color substitution chart.
The notebook acrostic spelled MEERAJARS, leading to the Instagram account meerajars.
The supplied rack.png showed two shelves with 26 jars. The decisive instructions were not in ordinary PNG text metadata: 600 bytes were appended after the PNG's IEND boundary.
The appended instructions specified:
- Top shelf: odd numbers, left to right, beginning 1, 3, 5.
- Bottom shelf: even numbers, left to right, beginning 2, 4, 6.
- Select names with an unmatched middle letter: names of odd length.
- Put those jar numbers in ascending order.
- Read that list using
Block A: 5-9-1-7-2-6-4-3-8.
The selected ascending list was:
| Position in list | Jar number | Label |
|---|---|---|
| 1 | 2 | Clove |
| 2 | 3 | Thyme |
| 3 | 4 | Cumin |
| 4 | 7 | Sumac |
| 5 | 11 | Chili |
| 6 | 14 | Basil |
| 7 | 19 | Anise |
| 8 | 23 | Saffron |
| 9 | 25 | Paprika |
Applying the Block A positions gave jar numbers:
11, 25, 2, 19, 3, 14, 7, 4, 23The Instagram carousel supplied a letter/color key. Matching the selected cap colors produced:
| Jar | Decoded letter |
|---|---|
| Chili | F |
| Paprika | L |
| Clove | A |
| Anise | V |
| Thyme | O |
| Basil | R |
| Sumac | I |
| Cumin | N |
| Saffron | G |
The case explicitly requested lowercase alphabetic text, so the accepted flag was:
cryptic{flavoring}Result: accepted, +200 points.
Color correspondence involved visual hue matching across image sources, not a claim of exact pixel equality. The accepted word corroborated the interpretation. We did not need to recover every chart panel once all letters required by the selected jars were available.
Puzzle source: meerajars color-chart carousel.
Lesson: an image decoder may happily ignore bytes after the formal end of a file. Always inspect the file boundary as well as the rendered image.
Case 18 — The Dying Star
Technique: PNG LSB text, Base64, indexed word order, music-history research, and vinyl inscriptions.
The supplied telescope_1979.png was a 400×500 RGBA image. Reading the RGB least-significant bits at the start of the image recovered a short, 13-byte string:
hairoil672026This was an Instagram handle. An earlier detection threshold that expected a longer printable string could miss it, so inspecting short prefixes mattered.
The relevant Instagram post had caption what? #i5 and an encoded comment:
T05bNV0qQVs3XTp0aGVbMl06bWVzc2FnZVs0XS1lbmdpbmVlcuKAmXNbM10tc2lkZVs2XTo=Base64 decoding produced numbered words:
ON[5]*A[7]:the[2]:message[4]-engineer’s[3]-side[6]:Reordering the numbered fragments yielded the request for the engineer's message on side A. The caption supplied an interrogative cue, while the case's other clues—1979, radio, a dying star, and black plastic—pointed to Joy Division's Unknown Pleasures.
The album cover's pulsar connection supported that identification. The next step was to examine vinyl runout inscriptions rather than lyrics or track titles.
We first tried A PORKY PRIME CUT, mastering engineer George Peckham's signature. That was rejected. The accepted message was:
THIS IS THE WAYcryptic{7h15_15_7h3_w4y}Result: accepted, +200 points.
Historical qualification: the cited discography lists multiple pressings and inside/outside or A/B conventions. The inscription exists, but the same playing side is not labeled identically across every Unknown Pleasures pressing.
The profile's atomic-mass biography was a different lead later reused in Case 23; it was not the solution to Case 18.
Sources: puzzle Instagram profile, relevant post, Factory Records discography, Science Museum Group pulsar-related archive record.
Lesson: identify the requested information layer. The engineer's signature was nearby evidence, but the question wanted a message.
Case 19 — The Photograph
Technique: JPEG metadata, appended ciphertext, and Vigenère.
thorne_archive.jpg carried two separate clues:
| Location | Content |
|---|---|
XMP dc:description | Sanguis In Machina |
| Appended after the JPEG end marker | rlcn{bue_toua_ens_zexlz_gharpl} |
Using MACHINA as the Vigenère key decrypted the appended ciphertext to:
flag{the_host_was_never_thorne}The decoded wrapper was flag{...}, but the website required cryptic{...}. We changed the wrapper and applied the event substitutions to the answer:
cryptic{7h3_h057_w45_n3v3r_7h0rn3}Result: accepted, +200 points.
This also advanced the story: the “host” was not Thorne. That statement is part of the fictional narrative, not an assertion about a real person.
Lesson: metadata can supply a key while another file region supplies the ciphertext. The two clues need not appear together visually.
Case 20 — Just a Picture
Technique: concatenated JPEG extraction, visual reading, Base64, and ROT13.
The supplied hollow_house.jpg contained two JPEG files concatenated together. Ordinary image viewers displayed the first and ignored the second.
The preserved byte offsets were:
| Boundary | Offset |
|---|---|
| First JPEG EOI marker begins | 32581 |
| Second JPEG SOI marker begins | 32583 |
Extracting bytes from 32583 onward produced a 600×400 notebook image. Its poem referred to a half-turn and thirteen paces, suggesting ROT13. The text also included a Base64 string:
SGFlbmkzeXkzcV9ZNGwzZUZfVTFxcTNhXzFhX0N5NDFhX0YxdHVn=Base64 decoding gave:
Haeni3yy3q_Y4l3eF_U1qq3a_1a_Cy41a_F1tugROT13 then produced:
Unrav3ll3d_L4y3rS_H1dd3n_1n_Pl41n_S1ghtThe case instructed us to paste the recovered content exactly:
cryptic{Unrav3ll3d_L4y3rS_H1dd3n_1n_Pl41n_S1ght}Result: accepted, +200 points.
The accepted record and later board state establish the solve. The board screenshot at the beginning of this article shows Case 20 closed alongside Cases 21 and 22.
Lesson: checking only the final bytes of a JPEG would miss this structure because the second JPEG also ends normally. Enumerate start and end markers throughout the file.
Case 21 — Last Stop
Technique: map identification, matching architectural clues, coordinate lookup, and rounding.
The narrator's mother described leaving a train at the last stop before a sanatorium, then visiting a ruin with a forest on its roof and a path built across it. A supplied map had its names removed except for Eisenbahnlinie, German for railway line.
The setting was Beelitz-Heilstätten. The ruin was Alpenhaus, whose roof had been reclaimed by vegetation and was crossed by a treetop walkway. The official operator's description supported the match.
The accompanying Proton document specified:
- Latitude and longitude rounded to three decimal places.
- The ruin's commonly used one-word name.
The recorded station coordinates were approximately:
52.26211, 12.92553Rounded as requested:
52.262, 12.926Combining these with Alpenhaus, converted to 4lp3nh4u5, gave:
cryptic{52.262_12.926_4lp3nh4u5}Result: accepted, +200 points.
The coordinates were for the station, not the ruin, the entire hospital grounds, or an unrelated nearby map marker. We encountered differing coordinates in other records, so the object being measured had to remain explicit.
Sources: official Alpenhaus description, operator's visitor flyer, station map record used in the solve, historical railway page.
Lesson: answer each requested field separately. A location riddle can require both a transport endpoint and a landmark, with different coordinates and names.
Case 22 — Last Review
Technique: EXIF metadata, landmark identification, Vigenère, a film-review profile, Base64, and ROT13.
The file window_day19.jpg showed a tower framed by a ruined arch. Its EXIF ImageDescription said:
key = the name of what I stare at. One word, no spaces.The EXIF UserComment contained:
KTIFVG_The tower was Chand Minar, at Daulatabad. Vigenère decryption with CHANDMINAR yielded:
IMISSU_The case described watching films and leaving written reactions, suggesting Letterboxd. The profile imissu_ existed and contained 15 film entries.
We read both review pages and revealed the spoiler-hidden text. Several reviews contained coded messages:
| Review | Encoded clue | Decoded result |
|---|---|---|
| The Machinist | S0VFUCBTRUFSQ0hJTkc= | Base64 → KEEP SEARCHING |
| Memento | GFIM ZILFMW | Atbash → TURN AROUND |
| Shutter Island | WKLV LV QRW LW | Caesar shift → THIS IS NOT IT |
| The Lighthouse | Longer Base64 string | Actual flag after a second transformation |
The Lighthouse review said that sometimes a message must be unwrapped before it can be turned around. Its encoded text was:
cGVsY2d2cHt1M181NzBjYzNxXzRhNWozZTFhdF83dTNfcDR5eTV9Base64 decoding gave:
pelcgvp{u3_570cc3q_4a5j3e1at_7u3_p4yy5}ROT13 recovered the complete flag:
cryptic{h3_570pp3d_4n5w3r1ng_7h3_c4ll5}Result: accepted, +200 points. The board reached 22/43 closed and 3,100 points.
Sources: Letterboxd profile, older review page, The Lighthouse review.
Lesson: a collection of encoded strings can contain both directions and decoys. Decode each in context; do not assume the first readable result is the answer.
Case 23 — The Scientist's Secret: incomplete investigation
Status: unresolved in our record. No accepted flag is known.
This is the unfinished trail at the end of the preserved investigation. The intermediate decodes below are confirmed; the final answer is not.
The brief described an atomic scientist's journal and five entries spelling a location. Crucially, the requested final format was:
cryptic{name_of_his_work}That asks for the name of the scientist's work or creation, not merely the intermediate location.
The supplied log_rot13_1946.jpg had an appended string after its JPEG end marker:
LHqTpTAgBKOvESxmGJcOrH5aCG0=The confirmed transformation chain was:
ROT13
→ YUdGcGNtOXBiRFkzTWpBeU5nPT0=
Base64
→ aGFpcm9pbDY3MjAyNg==
Base64
→ hairoil672026This returned to the Instagram account from Case 18, but a different clue was relevant. Its biography contained:
10.81 126.90 39.10 126.90 58.69These approximate atomic masses mapped to:
| Mass | Element | Symbol |
|---|---|---|
| 10.81 | Boron | B |
| 126.90 | Iodine | I |
| 39.10 | Potassium | K |
| 126.90 | Iodine | I |
| 58.69 | Nickel | Ni |
The symbols spell BIKINI. Combined with 1946 in the filename, this suggested Bikini Atoll and its nuclear-test history. That was a research lead, not an accepted final answer.
The site rejected fully converted candidates based on Bikini, Bikini Atoll, Operation Crossroads, Crossroads, Baker, Castle Bravo, Helen of Bikini, Fat Man, Hydrogen Bomb, Shrimp, and Demon Core. These rejections do not establish an alternative solution.
An attempted Crossroads Baker submission was not confirmed because browser control failed. The page became unresponsive, then remained at sign-in verification after a reload. We did not obtain another reliable verdict.
Local steghide attempts with a small set of Bikini-derived passwords also failed. That only rules out those particular extraction attempts; it does not prove that every steganographic scheme was absent.
The main reasoning failure was continuing to generate historically associated names without first identifying the scientist and the specific creation the question requested. Future work should resolve that evidence gap rather than expanding a list of guesses.
The story between the puzzles
We saved Transmission / Story Entry 4. In it, the fictional narrator described difficulty sleeping, exhaustion, nausea, withdrawing from work and social life, and being able to concentrate only on the mother's research. The narrator repeatedly returned to the same files, convinced something had been missed.
That passage echoed the case briefs and may connect to Case 19's message:
the host was never thorneThis connection remained an interpretation. We did not prove a final explanation of the story or complete the remaining cases, so there is no definitive ending to report here.
The transmission's descriptions concern a fictional character. They are not statements about the player or anyone's real health.

Transmission / Story Entry 4, preserved as part of the fictional investigation.
Reproducible decoding examples
These small examples explain the transformations. They are focused reproductions, not a replacement for retaining the original artifacts.
Vigenère decryption while preserving punctuation
The key advances only on alphabetic characters:
def vigenere_decrypt(text, key):
shifts = [ord(c.upper()) - ord('A') for c in key if c.isalpha()]
out = []
j = 0
for c in text:
if c.isascii() and c.isalpha():
base = ord('A') if c.isupper() else ord('a')
out.append(chr((ord(c) - base - shifts[j % len(shifts)]) % 26 + base))
j += 1
else:
out.append(c)
return ''.join(out)
assert vigenere_decrypt('TLBUXJD_AOFITBO_3', 'BLOOD') == 'SANGUIS_MACHINA_3'
assert vigenere_decrypt('KTIFVG_', 'CHANDMINAR') == 'IMISSU_'Inspect PNG trailing data
Walk PNG chunks to find the actual IEND boundary. Do not merely search for the letters IEND, which could occur inside another chunk's data:
from pathlib import Path
data = Path('rack.png').read_bytes()
assert data[:8] == b'\x89PNG\r\n\x1a\n'
offset = 8
while offset + 12 <= len(data):
length = int.from_bytes(data[offset:offset + 4], 'big')
kind = data[offset + 4:offset + 8]
end = offset + 12 + length # length + type + payload + CRC
if end > len(data):
raise ValueError('Truncated PNG chunk')
if kind == b'IEND':
print(data[end:].decode('utf-8', errors='replace'))
break
offset = endRecover the short RGB LSB prefix from Case 18
This reads RGB channels in row-major order and interprets successive bits most-significant-bit first within each byte:
from PIL import Image
import numpy as np
rgb = np.asarray(Image.open('telescope_1979.png').convert('RGB'))
bits = (rgb.reshape(-1) & 1).astype(np.uint8)
prefix = np.packbits(bits[:8 * 64]).tobytes()
print(prefix.split(b'\x00', 1)[0])
# b'hairoil672026'This particular order worked for the supplied PNG. It is not a universal LSB convention, and recompressing an image as JPEG can destroy such a payload.
Split the concatenated JPEG in Case 20
from pathlib import Path
data = Path('hollow_house.jpg').read_bytes()
assert data[32581:32583] == b'\xff\xd9'
assert data[32583:32586] == b'\xff\xd8\xff'
Path('hidden.jpg').write_bytes(data[32583:])The offsets belong to our preserved challenge file. For another file, inspect its structure first rather than reusing these numbers.
Decode the final Case 22 payload
import base64
import codecs
encoded = 'cGVsY2d2cHt1M181NzBjYzNxXzRhNWozZTFhdF83dTNfcDR5eTV9'
layer1 = base64.b64decode(encoded).decode('ascii')
flag = codecs.decode(layer1, 'rot13')
assert flag == 'cryptic{h3_570pp3d_4n5w3r1ng_7h3_c4ll5}'
print(flag)Focused reconstruction of the cake's successful QR grid
The original search tried multiple candidate grids. This example uses only the parameters that actually succeeded:
import cv2
import numpy as np
import zxingcpp
image = cv2.imread('case11-cake-realigned.png', cv2.IMREAD_GRAYSCALE)
n = 33
side = 928
x0 = y0 = 112
centers = (np.arange(n) + 0.5) * (side / n)
xx, yy = np.meshgrid(
np.float32(x0 + centers), np.float32(y0 + centers)
)
samples = cv2.remap(image, xx, yy, cv2.INTER_LINEAR)
_, grid = cv2.threshold(samples, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
# White is 255; black is 0. Restore only standard positioning structures.
finder = np.zeros((7, 7), dtype=np.uint8)
finder[1:6, 1:6] = 255
finder[2:5, 2:5] = 0
for x, y in [(0, 0), (n - 7, 0), (0, n - 7)]:
grid[max(0, y - 1):min(n, y + 8), max(0, x - 1):min(n, x + 8)] = 255
grid[y:y + 7, x:x + 7] = finder
for i in range(8, n - 8):
grid[6, i] = grid[i, 6] = 0 if i % 2 == 0 else 255
grid = cv2.copyMakeBorder(grid, 4, 4, 4, 4, cv2.BORDER_CONSTANT, value=255)
grid = cv2.resize(grid, None, fx=5, fy=5, interpolation=cv2.INTER_NEAREST)
results = zxingcpp.read_barcodes(
grid, formats=zxingcpp.BarcodeFormat.QRCode, is_pure=True
)
for result in results:
if result.valid:
print(result.text.strip())This is based on our saved successful search implementation. Package APIs can change, so retain the original environment or adjust the invocation if reproducing it later. The original local environment used OpenCV 4.13.0.92.
Accepted-flag reference table
This table preserves the recorded accepted strings, including exceptions to the general substitution rule.
| Case | Title | Accepted flag |
|---|---|---|
| 1 | Not recorded | Unknown; already solved |
| 2 | The Vampire's Obol | cryptic{8.7273} |
| 3 | Blood Remembers | cryptic{54NGU15_M4CH1N4_3} |
| 4 | Hexed | cryptic{d0_n07_7ru57_7h3_v01c35} |
| 5 | The Unsent Draft | cryptic{1_4m_th3_v3ss3l_n0w} |
| 6 | The Admins Symphony | cryptic{katzs_delicatessen} |
| 7 | The Sedation | cryptic{m07h_h4rv4rd_m4rk_11} |
| 8 | Synesthesia | cryptic{1t_l1st3ns_thr0ugh_th3_w1r3s} |
| 9 | The Living Tool | cryptic{2002.0251.01_102738727} |
| 10 | Withdrawn Paper | cryptic{8r0wn5h34dl1gh7h0u53_v3553l} |
| 11 | Paper Found | cryptic{4771C} |
| 12 | INTERCEPT-K | cryptic{MAO_1410} |
| 13 | CATCH | cryptic{5w337_80x} |
| 14 | Look Inside | cryptic{v15h4l} |
| 15 | Dead Air | cryptic{4625_811_290} |
| 16 | The Unsent Confession | Unknown; appeared solved on resumption |
| 17 | Mise en Place | cryptic{flavoring} |
| 18 | The Dying Star | cryptic{7h15_15_7h3_w4y} |
| 19 | The Photograph | cryptic{7h3_h057_w45_n3v3r_7h0rn3} |
| 20 | Just a Picture | cryptic{Unrav3ll3d_L4y3rS_H1dd3n_1n_Pl41n_S1ght} |
| 21 | Last Stop | cryptic{52.262_12.926_4lp3nh4u5} |
| 22 | Last Review | cryptic{h3_570pp3d_4n5w3r1ng_7h3_c4ll5} |
| 23 | The Scientist's Secret | Unresolved; no accepted flag |
| 24–43 | Not reached in this record | No walkthrough available |
What we would change next time
Read the answer schema before investigating
“Find the location,” “name the work,” “give the catalogue ID,” and “use the first name” are different tasks. Cases 9, 14, 21, and 23 show why those distinctions matter. Write the requested fields at the top of the notes and check each proposed answer against them.
Start with cheap structural checks
Before expensive steganography experiments, inspect the true file format, metadata, image dimensions, formal end markers, and trailing bytes. These checks directly solved or advanced Cases 7, 10, 17, 19, 20, 22, and 23.
Stop repeating an unproductive test family
The cake investigation spent too long on broad scans and increasingly distant interpretations. After enough negative results, the right move was to change the model: sample a structured QR grid instead of asking the same detector to recognize a photograph again.
Distinguish evidence from a good story
Real grave dates, nearby catalogue IDs, a matching album, or an associated nuclear test can all be true and still be the wrong answer. Retain three separate labels in notes: observed, inferred, and accepted.
Preserve original files and exact intermediate strings
The successful QR parameters, JPEG offsets, 13-byte username, book-cipher normalization, and literal partial-leet flags would all be difficult to reproduce from memory alone.
Credit the collaboration accurately
I supplied moderator hints, corrected interpretations, found the GitHub cake fragment, and provided board screenshots. AI assistance supported browser interaction, research, local scripts, extraction, and hypothesis testing. The investigation was collaborative, with several breakthroughs coming from revisiting an interpretation together.