Skip to content

Commit a13906a

Browse files
JOYclaude
andcommitted
docs: update architecture with V2 scoring engine, extension fast path, 13 sources
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent ce32181 commit a13906a

1 file changed

Lines changed: 255 additions & 35 deletions

File tree

DOSafe-Architecture.md

Lines changed: 255 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# DOSafe — System Architecture
22

3-
**Updated:** 2026-03-08
4-
**Status:** AI Detection (Phase 1–5.5) COMPLETE. Threat Intel Pipeline COMPLETE. Audio/Video TODO.
3+
**Updated:** 2026-03-10
4+
**Status:** AI Detection COMPLETE. Threat Intel Pipeline COMPLETE (1.52M+ entries, 13 sources). Risk Scoring V2 COMPLETE. Chrome Extension Protection v0.5.4 COMPLETE. Audio/Video TODO.
55

66
**Implementation ownership:** Claude is the primary coding agent for architecture changes; this document is the handoff/reference source for Claude-first implementation.
77

@@ -205,7 +205,7 @@ public.subscriptions (
205205
## Safety Data Flow
206206

207207
```
208-
External threat sources (11 feeds)
208+
External threat sources (13 feeds)
209209
│ ScamSniffer, MetaMask, Phishing.Database, URLhaus,
210210
│ OpenPhish, checkscam.vn, admin.vn, scam.vn, etc.
211211
@@ -214,7 +214,7 @@ dosafe.raw_imports (staging)
214214
│ pg_cron: sync-threats-6h, sync-phishing-db, daily-scraped
215215
216216
217-
dosafe.threat_intel (1.2M+ entries)
217+
dosafe.threat_intel (1.52M+ entries)
218218
dosafe.threat_clusters (89k+ scammer groups)
219219
220220
├── DOSafe entity-check / url-check ← direct query (dosafe.threat_intel)
@@ -294,17 +294,22 @@ DOSafe/
294294
│ │ │ ├── page.tsx # Landing page
295295
│ │ │ └── ... # Static pages (about, pricing, privacy, terms)
296296
│ │ └── lib/ # Shared libraries
297-
│ │ ├── threat-intel.ts # Threat DB lookup/upsert
298-
│ │ ├── doschain.ts # DOS Chain EAS queries (viem)
299-
│ │ ├── dosafe-quota.ts # Quota management
300-
│ │ ├── trusted-domains.ts # Whitelisted domains
301-
│ │ ├── url-normalize.ts # URL normalization + hashing
302-
│ │ └── dosai-session.ts # Auth session validation
303-
│ └── extension/ # Chrome extension (Manifest V3)
297+
│ │ ├── entity-scoring.ts # V2 risk scoring engine (tiers, freshness, corroboration)
298+
│ │ ├── entity-web-search.ts # Web search + LLM entity analysis
299+
│ │ ├── threat-intel.ts # Threat DB lookup/upsert
300+
│ │ ├── doschain.ts # DOS Chain EAS queries (viem)
301+
│ │ ├── dosme-trust.ts # DOS.Me Identity API client
302+
│ │ ├── dosafe-quota.ts # Quota management
303+
│ │ ├── trusted-domains.ts # Whitelisted domains (44 entries)
304+
│ │ ├── url-normalize.ts # URL normalization + hashing
305+
│ │ └── dosai-session.ts # Auth session validation
306+
│ └── extension/ # Chrome extension (Manifest V3) — v0.5.4
304307
│ ├── manifest.json
305-
│ ├── popup.js/html/css # Extension popup UI
306-
│ ├── background.js # Service worker
307-
│ └── content-facebook.js # Facebook-specific content script
308+
│ ├── popup.html/css # Side panel UI
309+
│ ├── background.js # Service worker + icon badge management
310+
│ ├── protection-content.js # Real-time URL protection overlay
311+
│ ├── content-facebook.js # Facebook-specific content script
312+
│ └── content-dosafe-auth.js # Extension auth callback
308313
├── supabase/
309314
│ ├── functions/
310315
│ │ ├── dosafe-telegram/ # Telegram bot (Deno 2 Edge Function)
@@ -382,39 +387,62 @@ Input image (≤10MB, JPEG/PNG/WEBP/GIF)
382387

383388
### 3. URL/Domain Scam Check (`/api/url-check`)
384389

385-
Hybrid DB-first + runtime fallback check. See [threat-intel.md](threat-intel.md) for full details.
390+
Hybrid DB-first + runtime check pipeline. Uses V2 scoring engine with source tiers, freshness decay, and corroboration bonus. See [threat-intel.md](threat-intel.md) for DB details.
386391

387392
```
388393
Input URL
394+
395+
├── 0. Typosquatting detection (sync, <1ms)
396+
│ └── Levenshtein distance + homoglyph normalization vs 44 trusted domains
389397
390398
├── 1. DB lookup (dosafe.threat_intel) — <10ms
391399
│ ├── Hash URL → lookup_threats()
392-
│ └── Hash domain → lookup_threats()
400+
│ └── Hash domain → lookup_threats() (skip for trusted domains)
393401
394-
├── 2. Runtime checks (parallel)
395-
│ ├── Trusted domain whitelist
396-
│ ├── Google Safe Browsing
402+
├── 2. Phase 1: Runtime checks (parallel)
403+
│ ├── Trusted domain whitelist (44 major platforms)
404+
│ ├── Google Safe Browsing API v4
397405
│ ├── WHOIS/RDAP domain age
398-
│ ├── Web search corroboration (Serper → SerpApi fallback)
406+
│ ├── Web search via searchEntityWeb() (Serper → SerpApi, 8 results)
399407
│ └── DOS Chain on-chain attestations
400408
401-
├── 3. Risk assessment (combines all signals)
402-
│ → critical / high / medium / low / safe
409+
├── 3. Phase 2: LLM Analysis (sequential, after Phase 1)
410+
│ └── analyzeEntityLLM() — Qwen3.5-35B analyzes web results
411+
│ + threat intel summary → structured signals + Vietnamese summary
412+
413+
├── 4. V2 Risk Scoring (computeRiskScoreV2)
414+
│ ├── Signal weights × source tier multiplier × freshness factor
415+
│ ├── Corroboration bonus (2+ independent sources)
416+
│ ├── Confidence level (low / medium / high)
417+
│ └── → riskScore (0–100) + riskLevel + confidence
403418
404-
└── 4. Cache runtime result (fire-and-forget, 7-day TTL)
419+
└── 5. Cache runtime result (fire-and-forget, 7-day TTL)
420+
421+
Extension fast path (X-Client-Type: extension):
422+
Skips: WHOIS, web search, LLM, on-chain, session check, quota
423+
Only: DB lookup + Safe Browsing + trusted domain + typosquatting
405424
```
406425

426+
**Response:** `riskScore`, `riskLevel`, `confidence`, `riskSignals[]`, `webAnalysis`, `llmSummary`, `typosquatting`, `threatIntel`, `onChain`
427+
407428
### 4. Entity Risk Check (`/api/entity-check`)
408429

409-
Check risk for phone numbers, wallets, emails, bank accounts, etc.
430+
Check risk for phone numbers, wallets, emails, bank accounts, etc. Uses same V2 scoring engine.
410431

411432
```
412433
Input: { entityType, entityId }
413434
414-
├── dosafe.threat_intel DB lookup — primary source (1.2M+ entries)
415-
├── DOS Chain EAS query — on-chain attestations (15s timeout)
416-
└── (Planned) DOS-Me Trust API — community flags from other products
417-
→ Combined risk assessment + riskSignals + cluster linking
435+
├── Phase 1 (parallel)
436+
│ ├── dosafe.threat_intel DB lookup — 1.52M+ entries
437+
│ ├── DOS Chain EAS query — on-chain attestations (15s timeout)
438+
│ ├── DOS.Me Identity API — member trust score, flags, DOS ID
439+
│ └── Web search (Serper → SerpApi) — 8 results (skip for bulk)
440+
441+
├── Phase 2 (sequential)
442+
│ └── LLM Analysis (analyzeEntityLLM) — structured signals + Vietnamese summary
443+
444+
└── V2 Scoring (computeRiskScoreV2)
445+
→ riskScore + riskLevel + confidence + riskSignals + llmSummary
418446
```
419447

420448
**Supported types:** phone, email, wallet, url, domain, bank_account, national_id, telegram, facebook, organization
@@ -427,12 +455,15 @@ Bilingual: Vietnamese + English (auto-detected)
427455
Quota: 20 checks/day per chat
428456
Calls: `dosafe.io/api/*` internally (via `DOSAFE_API_URL` secret)
429457

430-
### 6. Chrome Extension (`apps/extension`)
458+
### 6. Chrome Extension (`apps/extension`) — v0.5.4
431459

460+
- **Real-time URL protection**: Auto-checks current tab URL via `/api/url-check` with `X-Client-Type: extension` fast path
461+
- **Icon badge**: Green ✓ (safe/low), Yellow ! (medium), Red ✗ (high/critical) on extension icon
462+
- **Warning overlay**: Full-page overlay for high/critical risk — localized (vi/en), human-readable signal names, real DB sources
432463
- AI text detection on selected text or full page
433-
- URL scam check on current page
434464
- Facebook profile analysis (content script)
435465
- Side panel results display
466+
- Auth via `dosafe.io/auth/extension-callback`
436467

437468
### 7. Mobile App (Flutter — `DOSafe-Mobile`)
438469

@@ -446,7 +477,7 @@ Calls: `dosafe.io/api/*` internally (via `DOSAFE_API_URL` secret)
446477
Detailed in [threat-intel.md](threat-intel.md).
447478

448479
**Summary:**
449-
- **1.2M+ entries** from 11 sources: Phishing.Database (~711k), ScamSniffer (346k), MetaMask (234k), Tín Nhiệm Mạng (97k), ChongLuaDao (34k), URLhaus (23k), checkscam.vn (13k), scam.vn (10k), admin.vn (963), OpenPhish, ScamVN
480+
- **1.52M+ entries** from 13 sources: Phishing.Database (~450k), ScamSniffer (346k), nTrust/NCA (252k), MetaMask (234k), Tín Nhiệm Mạng (97k), TrueCaller (40k), ChongLuaDao (34k), checkscam.vn (27k), URLhaus (26k), scam.vn (10k), admin.vn (963), OpenPhish
450481
- **Schema:** `dosafe.threat_intel` + `dosafe.threat_clusters` (89k+ cluster links)
451482
- **Entity types:** domain, url, wallet, phone, bank_account, facebook, email, name
452483
- **Sync schedules (pg_cron):**
@@ -466,6 +497,189 @@ dosafe.threat_intel
466497

467498
---
468499

500+
## Risk Scoring Engine V2
501+
502+
**Implementation:** `src/lib/entity-scoring.ts` — shared engine used by both `/api/url-check` and `/api/entity-check`.
503+
504+
### Concept
505+
506+
The V1 scoring system used flat signal weights — every source contributing the same amount regardless of quality, freshness, or corroboration. This led to:
507+
508+
- **False positives**: Crowdsourced Vietnamese sources (scam.vn, checkscam.vn) flagging major platforms like google.com
509+
- **Stale data inflation**: Year-old reports from a single unverified source scoring as high-risk
510+
- **No confidence signal**: Users couldn't tell if a "medium risk" was backed by 5 authoritative sources or 1 crowdsourced report
511+
512+
V2 solves these with 5 mechanisms: **source tiers**, **freshness decay**, **corroboration bonus**, **confidence levels**, and **typosquatting detection**.
513+
514+
### Design Principles
515+
516+
1. **No single source determines verdict alone** — base score is 15 (low), signals add/subtract
517+
2. **Higher-quality sources have more influence** — Google Safe Browsing (tier 1) carries more weight than runtime_cache (tier 4)
518+
3. **Recent reports weigh more** — a phishing report from yesterday is more relevant than one from 2 years ago
519+
4. **Multiple independent sources increase confidence** — 3 sources saying "scam" is more trustworthy than 1
520+
5. **Trusted domains bypass domain-level DB lookup** — prevents false positives from crowdsourced reports on major platforms
521+
522+
### Source Tiers
523+
524+
Each threat intel source is classified into a quality tier. The tier multiplier scales the signal's base weight.
525+
526+
| Tier | Multiplier | Sources | Rationale |
527+
|------|-----------|---------|-----------|
528+
| **1 — Authoritative** | 1.0 | Google Safe Browsing, Tín Nhiệm Mạng (NCSC VN), tinnhiemmang_trusted_webs/orgs | Government/industry authority, low false positive rate |
529+
| **2 — Curated Security** | 0.85 | MetaMask, Phishing.Database, ScamSniffer, URLhaus, OpenPhish | Security teams with review processes |
530+
| **3 — Crowdsourced VN** | 0.70 | checkscam.vn, scam.vn, admin.vn, nTrust/NCA, TrueCaller, ChongLuaDao | Community-driven, higher noise, valuable for VN-specific threats |
531+
| **4 — Heuristic** | 0.50 | runtime_cache | Our own cached results, may be stale or from incomplete checks |
532+
533+
**Scoring formula for DB signals:**
534+
```
535+
effective_weight = base_weight × tier_multiplier × freshness_factor
536+
```
537+
538+
For non-DB signals (on-chain, DOS.Me, web search, URL-specific), base weight is used directly.
539+
540+
### Freshness Decay
541+
542+
Reports decay in influence as they age, measured by `last_seen_at`:
543+
544+
| Age | Factor | Rationale |
545+
|-----|--------|-----------|
546+
| ≤ 30 days | 1.0 | Fresh, highly relevant |
547+
| ≤ 90 days | 0.85 | Recent, still relevant |
548+
| ≤ 365 days | 0.70 | Aging, may no longer be active |
549+
| ≤ 2 years | 0.50 | Old, likely inactive but retain historical context |
550+
| > 2 years | 0.30 | Very old, minimal influence — scam sites almost certainly dead |
551+
552+
If `last_seen_at` is null: factor = 0.70 (treat as aging).
553+
554+
### Corroboration Bonus
555+
556+
Multiple independent risk sources increase the score and confidence:
557+
558+
| Unique risk sources | Bonus |
559+
|---------------------|-------|
560+
| 4+ | +20 |
561+
| 3 | +15 |
562+
| 2 | +10 |
563+
| 1 | 0 |
564+
565+
Sources counted: all DB sources (excluding `google_safe_browsing` for "clean" results and `runtime_cache`), plus `onchain` and `google_safe_browsing` when they report actual threats.
566+
567+
### Confidence Levels
568+
569+
Returned alongside riskScore to help UIs and downstream consumers calibrate trust:
570+
571+
| Level | Criteria |
572+
|-------|----------|
573+
| **high** | 3+ unique risk sources, OR tier 1 source + 2+ total sources |
574+
| **medium** | 2+ unique risk sources, OR 1 tier 1 source |
575+
| **low** | 0–1 risk sources, no tier 1 |
576+
577+
### Typosquatting Detection
578+
579+
Detects domains that visually resemble trusted brands:
580+
581+
1. **Levenshtein distance**: Compares domain base name against 44 trusted domains. Distance 1–2 for domains ≥ 5 chars, distance 1 for shorter.
582+
2. **Homoglyph normalization**: Cyrillic `а``a`, `е``e`, `0``o`, `1``l`, etc. — catches `gооgle.com` (Cyrillic o's).
583+
3. **Signal**: `typosquatting_suspected` (+25 weight) with `similarTo` field identifying the targeted brand.
584+
585+
### Signal Weights Reference (V2)
586+
587+
#### Threat DB Signals (× tier × freshness)
588+
589+
| Signal | Base Weight |
590+
|--------|------------|
591+
| `db_flagged_phishing` | +85 |
592+
| `db_flagged_malware` | +80 |
593+
| `db_flagged_fraud` | +75 |
594+
| `db_flagged_scam` | +70 |
595+
| `db_flagged_spam` | +50 |
596+
| `db_flagged_robocall` | +45 |
597+
| `db_flagged_unwanted` / `db_flagged_political` | +40 |
598+
| `db_verified_legitimate` | −40 |
599+
| `db_verified_clean` | −25 |
600+
| `db_very_high_report_count` (≥1000 reports) | +35 |
601+
| `db_high_report_count` (≥100 reports) | +20 |
602+
| `cluster_linked` | +12 |
603+
604+
#### On-Chain Signals (no tier reduction)
605+
606+
| Signal | Weight |
607+
|--------|--------|
608+
| `onchain_flagged_phishing` | +85 |
609+
| `onchain_flagged_scam` | +70 |
610+
| `onchain_high_risk` (≥80) | +60 |
611+
| `onchain_medium_risk` (50–79) | +30 |
612+
| `onchain_verified_legitimate` | −40 |
613+
| `onchain_trusted` (<20) | −25 |
614+
615+
#### DOS.Me Identity Signals
616+
617+
| Signal | Weight |
618+
|--------|--------|
619+
| `dosme_member_flagged` | +40 |
620+
| `dosme_trust_passing` | −20 |
621+
| `dosme_high_trust` | −15 |
622+
| `dosme_multi_verified` | −10 |
623+
| `dosme_medium_trust` / `dosme_has_dosid` | −5 |
624+
625+
#### Web Search + LLM Signals
626+
627+
| Signal | Weight |
628+
|--------|--------|
629+
| `web_identified_scam` | +55 |
630+
| `web_scam_reports` | +35 |
631+
| `web_spam_reports` | +25 |
632+
| `web_identified_brand` | −15 |
633+
| `web_identified_government` | −25 |
634+
| `web_mixed_signals` | +8 |
635+
636+
#### URL-Specific Signals (extra weights in url-check only)
637+
638+
| Signal | Weight |
639+
|--------|--------|
640+
| `safe_browsing_malware` / `safe_browsing_social_engineering` | +90 |
641+
| `safe_browsing_unwanted_software` | +70 |
642+
| `safe_browsing_potentially_harmful_application` | +60 |
643+
| `new_domain` (<30 days) | +25 |
644+
| `young_domain` (<90 days) | +10 |
645+
| `trusted_domain` | −40 |
646+
| `typosquatting_suspected` | +25 |
647+
648+
### Score → Risk Level
649+
650+
| Score | Level |
651+
|-------|-------|
652+
| 0–19 | `safe` |
653+
| 20–49 | `low` |
654+
| 50–74 | `medium` |
655+
| 75–89 | `high` |
656+
| 90–100 | `critical` |
657+
658+
### Web Search + LLM Pipeline
659+
660+
**Implementation:** `src/lib/entity-web-search.ts`
661+
662+
The V1 URL pipeline used simple keyword matching (`hasScamTerms()`) on web search results. V2 replaces this with a full LLM analysis pipeline:
663+
664+
```
665+
1. searchEntityWeb(entityType, entityId)
666+
└── Builds entity-type-aware query (phone: local+intl format, domain: +scam/review terms)
667+
└── Serper → SerpApi fallback, 8 results
668+
669+
2. analyzeEntityLLM(entityType, entityId, webResults, threatIntelSummary)
670+
└── Qwen3.5-35B-A3B-GPTQ-Int4 (api.dos.ai)
671+
└── Compact prompt: entity + top 5 results (120-char snippets) + threat intel summary
672+
└── Returns: entity_identity, risk_level, risk_score, signals[], summary (Vietnamese)
673+
└── max_tokens=250, temperature=0.1
674+
675+
3. getWebSignals(webAnalysis)
676+
└── Filters LLM signals to valid set: web_identified_scam, web_scam_reports, etc.
677+
```
678+
679+
**Performance:** Web search runs parallel with Phase 1 (DB/on-chain/DOS.Me). Only LLM analysis waits for Phase 1 results. Total added latency: ~3–5s for full path (skipped on extension fast path).
680+
681+
---
682+
469683
## Database Layout
470684

471685
### Supabase Schemas
@@ -480,7 +694,7 @@ dosafe.threat_intel
480694

481695
| Table | Schema | Purpose |
482696
|-------|--------|---------|
483-
| `threat_intel` | dosafe | Unified threat data (1.2M+ entries, all sources) |
697+
| `threat_intel` | dosafe | Unified threat data (1.52M+ entries, all sources) |
484698
| `threat_clusters` | dosafe | Scammer group linking (89k+ clusters) |
485699
| `raw_imports` | dosafe | Staging for scraped reports |
486700
| `sync_log` | dosafe | Sync health monitoring |
@@ -589,16 +803,22 @@ DOS_ME_TRUST_API_KEY=...
589803
- [x] Image detection (C2PA + EXIF/DCT + reverse search + LLM)
590804
- [x] Paraphrase shield + ESL de-biasing
591805
- [x] URL/domain scam check with on-chain integration
592-
- [x] URL/domain web-search corroboration layer (Serper → SerpApi fallback)
593806
- [x] Telegram bot with bilingual support
594-
- [x] Chrome extension
807+
- [x] Chrome extension with real-time URL protection (v0.5.4)
595808
- [x] Mobile app (Flutter, calls dosafe.io/api/*)
596-
- [x] Threat intelligence pipeline (1.2M+ entries, 11 sources)
809+
- [x] Threat intelligence pipeline (1.52M+ entries, 13 sources)
597810
- [x] Quota system (anonymous + authenticated)
598811
- [x] Vietnamese scraper pipeline (admin.vn + checkscam.vn + scam.vn → raw_imports → threat_intel)
812+
- [x] nTrust (NCA) + TrueCaller phone DB extraction (292k entries)
599813
- [x] Deep scraping with evidence image extraction + Supabase Storage upload
600814
- [x] Entity clustering (89k+ clusters)
601815
- [x] RAID benchmark submission (672k texts, AUROC 0.852)
816+
- [x] **Risk Scoring V2**: source tiers, freshness decay, corroboration bonus, confidence levels
817+
- [x] **Typosquatting detection**: Levenshtein + homoglyph normalization
818+
- [x] **LLM web search pipeline**: replaced keyword matching with Qwen3.5-35B analysis
819+
- [x] **Extension protection overlay**: localized (vi/en), human-readable signals, real DB sources
820+
- [x] **Partner API / DOS Shield Gateway**: `/api/v1/check`, `/check/bulk`, `/report`
821+
- [x] **DOS.Me Identity integration**: member trust score, flags, verified providers
602822

603823
### Planned
604824
- [ ] Sync confirmed flags to DOS-Me Trust API (`POST /trust/flags`)

0 commit comments

Comments
 (0)