Challenge
A malicious 'document classification model' has been recovered at the Rift perimeter. According to Headquarters' analysis, the model was trained on data containing classified documents, and traces of that data remain embedded in the model parameters. HQ attempted to extract the original data on that basis, but the model appears to contain deliberate obfuscation intended to hinder analysis.
Identify the seven English words that make up the classified document.
Flag format:
CDDC2026{1_2_3_4_5_6_7}(lowercase, alphabetical,_-joined)
Files: model.pkl, model_interface.py.
Recon
model_interface.py exposes a TF-IDF + logistic-regression classifier:
vocab : dict[str, int]—SHA256(token) → feature_index(so the vocabulary is one-way hashed)idf,coef,intercept— the usual TF-IDF/LR parametersngram_range = (1, 1),sublinear_tf = True,lowercase = True- 228 features
predict(text) returns SECRET when coef · vec + intercept > 0.
Because the vocabulary is hashed, there's no direct mapping back to words — but SHA256 is fast, so any candidate word can be hashed and looked up.
Coefficient inspection
Top features by coef:
velvet +2.0000 idf 3.6150
quantum +2.0000 idf 3.3273
prism +2.0000 idf 3.6150
obsidian +2.0000 idf 3.6150
gradient +2.0000 idf 3.3273
butterfly +2.0000 idf 3.6150 <-- 6 clamped "trigger" words
the +1.1384 idf 2.3157
remembers +1.0193 idf 2.3157
model +0.9524 idf 2.3157
fed +0.9524 idf 2.3157
it +0.9524 idf 2.3157
you +0.9524 idf 2.3157
everything +0.8911 idf 2.4110
...
The top six coefficients are all exactly +2.0 — a textbook sign of an
L2/clipping cap. They look like a list of unrelated noun-y words (velvet,
quantum, prism, obsidian, gradient, butterfly). That's only six
words, and the challenge asks for seven. These are the "deliberate
obfuscation": decoy tokens injected so that anyone who blindly takes
argsort(coef)[-k:] walks away with the wrong answer.
De-hashing the vocabulary
Downloaded dwyl/english-words/words_alpha.txt (~370k words) and brute-forced
the 228 SHA256 entries:
import joblib, hashlib
data = joblib.load("model.pkl")
vocab = data["vocab"]
matched = {}
for w in open("words_alpha.txt"):
w = w.strip().lower()
h = hashlib.sha256(w.encode()).hexdigest()
if h in vocab:
matched[vocab[h]] = w
# 226 / 228 recovered (the remaining 2 have small negative coefs — irrelevant)
226 of 228 features resolve cleanly. The two unmatched entries (idx 47,
idx 207) have negative coefficients and high IDF — not part of the secret.
Picking the real seven
After the six clamped decoys, the next tier of positive coefficients forms a coherent English sentence — and it's exactly seven words, all with the lowest IDF in the model (i.e. the model saw them often, consistent with being co-located in a single high-frequency training document):
"the model remembers everything you fed it"
This is a self-referential description of the model-inversion attack itself — a fitting "classified document" for the challenge.
Verification with the provided interface:
'the model remembers everything you fed it' -> SECRET, score 1.003029
Score safely > 0, all seven words contribute (any subset drops the score and
flips back to PUBLIC), and the sentence is grammatical English. The six
clamped trigger words are independent decoys (any one of them alone already
crosses the threshold; together they score +3.31), confirming they are noise
inserted to mislead naive top-k extraction.
Flag
Alphabetical: everything, fed, it, model, remembers, the, you
CDDC2026{everything_fed_it_model_remembers_the_you}
Takeaways
- "Top-k coefficient" is the obvious first cut for inverting a linear text classifier — but it's also the obvious place to hide decoys (here via weight clipping at +2.0).
- Hashed vocabularies are not protection: a dictionary brute-force against SHA256 finishes in seconds for a 200-feature model.
- The real signal in this model was the next tier of coefficients, where a low-IDF, semantically-coherent cluster betrayed a memorised training sentence — a clean illustration of how overfit LMs leak training data.