Bulwark Scam Detector

A multilingual scam / spam / legitimate message classifier, specialised for Turkish. Fine-tuned from Horizon-Labs/phishing-scam-detector-base (mmBERT-base, 307M parameters) to fix one specific weakness: false alarms on real Turkish institutional messages (bank, cargo, e-Devlet, operator, OTP notifications).

Code: github.com/SavienWalker/bulwark Β· Benchmark: SavienWalker/bulwark-bench-tr

πŸ‡ΉπŸ‡· TΓΌrkΓ§e ΓΆzet: Bulwark; SMS, e-posta ve kΔ±sa mesajlarΔ± dolandΔ±rΔ±cΔ±lΔ±k / spam / temiz olarak ayΔ±rΔ±r. GerΓ§ek TΓΌrk kurum mesajlarΔ±nda mevcut modelin temiz mesajlarΔ±n yarΔ±sΔ±na verdiği yanlış alarmΔ± %14'e indirir, istenmeyen mesajlarΔ± yakalama oranΔ± ise %98'de kalΔ±r. Diğer dillerdeki temel yeteneği korunmuştur.

Headline result

On a held-out half of real Turkish SMS from a personal inbox (opened once, after all model choices were made):

Base model (threshold 0.5) Bulwark (threshold 0.6)
False alarm on legitimate messages ↓ 53% (54/102) 14% (14/102)
Legitimate message labelled fraud ↓ 26% 9%
Unwanted (spam + fraud) caught ↑ 100% (52/52) 98% (51/52)
3-class accuracy ↑ 64% 87%

The base model flags roughly every second real bank / cargo / e-Devlet notification as unwanted because it was trained on synthetic scams plus generic web text, and has rarely seen what a real institutional message looks like. Bulwark keeps the base model's recall while learning the difference.

Labels and usage

id label meaning
0 legitimate genuine personal or institutional message
1 spam advertising from a real business
2 fraud tries to steal money, card data, passwords, codes, identity or trust

Recommended decision rule: treat a message as unwanted when p(spam) + p(fraud) > 0.6 (chosen on the development split; stored in bulwark_config.json).

import torch
from transformers import AutoTokenizer, AutoModelForSequenceClassification

model_id = "SavienWalker/bulwark-scam-detector"
tok = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForSequenceClassification.from_pretrained(model_id).eval()

text = "PTT: Gonderiniz adres eksikligi nedeniyle bekletilmektedir. 0,99 TL odeme yapin: ptt-gonderitakip.com"
with torch.no_grad():
    p = torch.softmax(model(**tok(text, return_tensors="pt", truncation=True, max_length=256)).logits, -1)[0]
probs = {model.config.id2label[i]: round(v.item(), 3) for i, v in enumerate(p)}
unwanted = probs["spam"] + probs["fraud"] > 0.6
print(probs, "unwanted" if unwanted else "ok")

Evaluation

All numbers compare the base model and Bulwark on the same messages. Sets are described in bulwark-bench-tr. Messages marked ambiguous (mostly illegal-betting ads) are excluded from metrics.

Set Type Metric Base Bulwark
Real SMS, test half (212) real, held out false alarm ↓ 53% 14%
unwanted caught ↑ 100% 98%
Real e-mail (40) real, development set false alarm ↓ 33% 19%
Hard set v2 (60) synthetic, human-reviewed fraud caught ↑ 82% 95%
false alarm ↓ 25% 0%
contrast pairs fully correct ↑ 9/13 12/13
Hard set v1 (42) synthetic, human-reviewed contrast pairs fully correct ↑ 5/7 7/7
UCI SMS Spam, held-out half (2,787) real, English unwanted caught ↑ 87% 96%
Multilingual probe (54; de, fr, es, pt, ru, ar) synthetic, easy 3-class accuracy 54/54 54/54

Contrast pairs are a fake message and the genuine message it imitates (e.g. fake vs. real HGS toll notice); a pair counts only if both are classified correctly β€” the clearest test of whether a model reads the signals (domain, request, tone) rather than the topic.

How to read these numbers honestly:

  • The only fully clean real-world number is the SMS test half. The e-mail set was used for error analysis, so it is reported as development data.
  • Hard sets and training templates were written by the same author (an LLM, Claude). A style overlap could inflate those scores. They are reported separately and labelled synthetic.
  • The SMS test half contains no non-ambiguous real fraud β€” real fraud in a personal inbox is almost all illegal betting. Fraud recall is therefore measured on the (synthetic) hard sets only.
  • English: half of the UCI SMS Spam Collection was used as replay data during training, so the English gain is in-distribution; the honest claim is "no regression", not "better than the base model".
  • Other languages: a small, easy probe shows no regression. Hard cases outside Turkish were not measured.

Training

  • Base: Horizon-Labs/phishing-scam-detector-base (Apache-2.0), itself built on jhu-clsp/mmBERT-base (MIT).
  • Data (~9k messages):
    • ~8k Turkish synthetic messages from 190 hand-written templates with slot filling (institution, amount, date, code, look-alike domain). Covers real institutional notifications, real-business ads, link-based phishing, and link-free social engineering. Patterns were drawn from public warnings (KGM, SGK, PTT, EGM) and public complaint narratives; no complaint text was copied.
    • ~1k English messages from the UCI SMS Spam Collection (CC BY 4.0) as replay against forgetting; spam vs. fraud for these was taken from the base model's own prediction (distillation).
  • Leakage control: every training message was compared with every evaluation message (token-set Jaccard); anything β‰₯ 0.5 was removed.
  • Personalisation balancing: scammers now use leaked personal data (name, card last 4 digits, plate, old address). These details were injected into legitimate and fraudulent training messages at equal rates, so that "the message knows my name" is not learned as a sign of legitimacy.
  • Recipe: word embeddings frozen (110M of 307M parameters trained), bf16, AdamW lr 2e-5, 2 epochs, max length 256, class-weighted loss, fraud examples down-sampled to the legitimate count. Runs on a single 6 GB laptop GPU (RTX 4050) in about 6 minutes.
  • Model selection: on a development half of the real SMS, split by sender so the same institution never appears in both halves.

Scope and limitations

  • One message at a time. Many real scams unfold over a phone call, a long WhatsApp conversation, a fake website or an ad. Bulwark sees only the text it is given; the first message of a slow scam often looks harmless.
  • A message containing your real personal details is not proof that it is genuine. Leaked databases make this trivial for scammers.
  • Illegal-betting ads are labelled fraud but treated as ambiguous in evaluation.
  • Small real evaluation sets (hundreds, not thousands). Treat the numbers as indicative.
  • Not a replacement for a bank's or carrier's own fraud systems. Do not use it to make decisions about people.

License and attribution

Apache-2.0. Derived from Horizon-Labs/phishing-scam-detector-base (Apache-2.0) and jhu-clsp/mmBERT-base (MIT). English replay data: Almeida, T.A. & GΓ³mez Hidalgo, J.M., SMS Spam Collection (UCI, CC BY 4.0).

Downloads last month
-
Safetensors
Model size
0.3B params
Tensor type
F32
Β·
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support

Model tree for SavienWalker/bulwark-scam-detector

Finetuned
(1)
this model

Dataset used to train SavienWalker/bulwark-scam-detector