Skip to content

Repository files navigation

ScamShield logo

ScamShield

Paste a link. Know if it’s safe to buy.

Evidence-first website risk analysis for online stores, listings, checkout pages, and payment links.

ScamShield landing page

ScamShield is a self-hosted consumer security application and Manifest V3 browser extension. It inspects independent technical and content signals, calculates a deterministic 0–100 risk score, and connects every warning to concrete evidence, a source, severity, confidence, and score contribution.

It does not sell subscriptions, require registration, let an LLM decide the score, submit checkout forms, or claim that a website is “definitely a scam.”

The answer comes first

ScamShield evidence report

Every report leads with a plain recommendation and then shows exactly why:

  • domain registration age, TLD and suspicious naming patterns;
  • brand impersonation, typo-squatting and homoglyph-style substitutions;
  • TLS availability and certificate validity;
  • business identity and contact details found on the page;
  • missing, conflicting or copied policy information;
  • cross-domain redirects, form actions and unknown checkout providers;
  • opaque payment links with amount/product data embedded in the URL;
  • cryptocurrency or bank-transfer payment warnings;
  • suspicious “official” or “unlimited” digital-access resale claims;
  • optional phishing/malware reputation matches;
  • positive evidence such as an established domain or valid HTTPS.

The screenshot above is a real regression case: a young direct-payment domain selling purported unlimited Claude access is now classified as 72/100 — HIGH RISK, with 94% confidence and seven inspectable observations.

ScamShield mobile risk report

Why the score is explainable

Detectors emit typed observations rather than verdicts:

{
  "signal": "opaque_direct_payment_link",
  "severity": "high",
  "risk_points": 18,
  "confidence": 0.95,
  "evidence": "The URL opens a direct payment flow with the amount and item supplied in query parameters, without a recognized payment provider.",
  "source": "Payment URL structure",
  "group": "checkout"
}

The risk engine is the only scoring authority. It:

  1. validates severity, confidence and detector group;
  2. keeps the strongest duplicate observation;
  3. applies confidence weighting and severity caps;
  4. combines correlated signals with diminishing returns;
  5. caps each detector family to prevent double counting;
  6. requires evidence from multiple independent groups for scores above 60;
  7. allows an exceptional score floor only for a high-confidence confirmed phishing, malware, or credential-theft source.

A new domain alone stays low risk when identity and policy evidence are otherwise healthy. A valid HTTPS certificate is shown as a positive transport signal, but never treated as proof that the merchant is legitimate.

Architecture

flowchart TD
    U[Web app or browser extension] -->|URL + anonymous browser ID| A[FastAPI]
    A --> V[URL normalization and public-IP preflight]
    V --> Q[Redis / Celery scan job]
    Q --> C[Isolated safe fetcher]
    Q --> D[RDAP + DNS + domain heuristics]
    Q --> T[TLS inspection]
    Q --> R[Reputation adapters]
    C --> X[Deterministic or validated AI extraction]
    X --> I[Identity / policy / checkout detectors]
    D --> N[Signal normalization]
    T --> N
    R --> N
    I --> N
    N --> E[Deterministic risk engine]
    E --> P[(PostgreSQL evidence snapshots)]
    P --> S[SSE progress + explainable report]
Loading

Independent checks run concurrently. Provider failures degrade to a skipped or partial check; one unavailable integration does not fail the entire scan or become a false “safe” result.

Anonymous private history

There are no accounts, email addresses, passwords, plans, payments, or daily product quotas. The web app creates a random identifier in local browser storage and sends it as X-ScamShield-Visitor. The API stores only an HMAC-SHA256 digest of that value to scope history, saved websites and monitoring records.

Clearing browser storage intentionally breaks the link to that private history. Users can export their data or delete all history from Settings.

Short burst and concurrent-job controls remain as security protections against accidental overload and automated abuse; they are not monetization limits.

Repository structure

ScamShield/
├── apps/
│   ├── web/            # Next.js consumer web app, EN/RU, light/dark
│   ├── api/            # FastAPI routes, detectors, providers and persistence
│   ├── worker/         # Celery scan and monitoring jobs
│   └── extension/      # Chrome/Chromium Manifest V3 extension
├── packages/
│   ├── ai/             # Pydantic-validated extraction + deterministic fallback
│   ├── crawler/        # SSRF-resistant HTTP fetcher
│   └── risk-engine/    # sole deterministic scoring authority
├── migrations/         # Alembic database migrations
├── tests/              # risk, detector, API, AI and crawler regression tests
├── docs/
│   ├── DEPLOYMENT.md
│   ├── PROVIDERS.md
│   └── SECURITY.md
├── docker-compose.yml
├── pyproject.toml
└── pnpm-workspace.yaml

Quick start

Requirements: Docker Desktop with Compose v2.

git clone https://github.com/rezvvent/ScamShield.git
cd ScamShield
docker compose up --build

Compose waits for PostgreSQL and Redis, applies migrations, seeds detector feature flags, and starts the API, worker, scheduler, object storage and web app.

Service URL
Web application http://localhost:3000
FastAPI http://localhost:8000
OpenAPI http://localhost:8000/docs
MinIO console http://localhost:9001

No external credential is required for deterministic scans. Optional provider checks clearly show when they are not configured.

Stop the stack with:

docker compose down

Local development

corepack enable
pnpm install
python3.12 -m venv .venv
.venv/bin/pip install -e '.[dev]'
.venv/bin/python scripts/seed.py

Run the API and web app in separate terminals:

.venv/bin/uvicorn scamshield_api.main:app --reload --app-dir apps/api --port 8000
pnpm --filter @scamshield/web dev

The default non-Docker API uses SQLite and inline scan execution. Docker uses PostgreSQL, Redis and Celery for production parity.

Environment variables

Copy .env.example to .env when overriding defaults.

Variable Purpose
SECRET_KEY HMAC secret for anonymous owner/IP digests; use 32+ random bytes
PUBLIC_APP_URL exact web origin and shared-report base URL
NEXT_PUBLIC_API_URL API origin embedded in the Next.js build and CSP
DATABASE_URL async SQLAlchemy PostgreSQL or SQLite URL
REDIS_URL Celery broker and result backend
SCAN_EXECUTION_MODE inline or celery
SCAN_MAX_REDIRECTS maximum revalidated redirect hops
SCAN_TOTAL_TIMEOUT_SECONDS whole fetch timeout
SCAN_MAX_BODY_BYTES maximum accepted HTML response size
SCAN_REQUESTS_PER_MINUTE technical burst protection
MAX_ACTIVE_SCANS_PER_VISITOR concurrent-job protection
RDAP_CACHE_HOURS, TLS_CACHE_HOURS, REPUTATION_CACHE_HOURS cache TTLs
GOOGLE_SAFE_BROWSING_API_KEY optional phishing/malware provider
OPENAI_API_KEY, OPENAI_MODEL optional structured extraction; never scoring
ADMIN_API_KEY optional internal feature-flag/stats API; empty disables it

If Docker cannot resolve public hosts while a VPN is active, set SCAMSHIELD_DNS to a DNS resolver reachable from Docker. Do not use this setting to bypass an organization’s network policy.

API

The web app and extension create the anonymous visitor ID automatically. Direct API clients should generate and retain a random value of at least 16 characters:

curl -X POST http://localhost:8000/api/v1/scans \
  -H 'Content-Type: application/json' \
  -H 'X-ScamShield-Visitor: random-client-id-keep-this-private' \
  -d '{"url":"https://example.com"}'

Core endpoints:

POST   /api/v1/scans
GET    /api/v1/scans/{id}
GET    /api/v1/scans/{id}/events
GET    /api/v1/scans
DELETE /api/v1/scans/{id}
POST   /api/v1/scans/{id}/share
GET    /api/v1/reports/shared/{slug}
GET    /api/v1/watch
POST   /api/v1/watch
DELETE /api/v1/watch/{id}
GET    /api/v1/data/export
DELETE /api/v1/data/history

Browser extension

Build the extension:

pnpm --filter @scamshield/extension build

Then:

  1. open chrome://extensions;
  2. enable Developer mode;
  3. choose Load unpacked;
  4. select apps/extension/dist;
  5. open a public website and click Scan this page.

For a hosted deployment:

SCAMSHIELD_API_URL=https://api.example.com \
SCAMSHIELD_APP_URL=https://scamshield.example.com \
pnpm --filter @scamshield/extension build

Permissions are limited to activeTab, scripting, storage, and configured API hosts. The extension never reads input values, cookies, authorization headers, local/session tokens, passwords, card values, or unrelated browsing history.

External providers

  • RDAP: available without credentials through the included adapter.
  • Google Safe Browsing: configure GOOGLE_SAFE_BROWSING_API_KEY; confirmed matches can activate the exceptional phishing/malware scoring path.
  • OpenAI: configure OPENAI_API_KEY; hostile page text is delimited as untrusted data, structured output is schema-validated, store: false is used, and failures fall back to deterministic extraction.
  • Additional providers: implement bounded adapters in providers.py, map observations to RiskSignal in detector code, and add clean/malicious/ambiguous/outage fixtures.

See Provider integration.

Quality checks

.venv/bin/ruff format --check apps packages scripts tests migrations
.venv/bin/ruff check apps packages scripts tests migrations
.venv/bin/pytest -q
pnpm --filter @scamshield/web typecheck
pnpm --filter @scamshield/web build
pnpm --filter @scamshield/extension typecheck
pnpm --filter @scamshield/extension build

The suite includes:

  • established legitimate store → low risk;
  • new suspicious store → high risk;
  • new legitimate startup → new domain alone stays low risk;
  • opaque direct-payment/unlimited-access regression → high risk;
  • confirmed phishing exception;
  • correlated-signal caps and deduplication;
  • loopback, cloud metadata, credentials, redirect and body-size SSRF protections;
  • prompt-injection isolation and malformed model-output fallback;
  • public mode with no registration or usage-plan endpoints.

Security model

Everything from a target website is hostile: URL, DNS response, redirects, headers, HTML, scripts, metadata, extracted text and embedded instructions.

  • only HTTP/HTTPS URLs are accepted;
  • credentials, internal hostnames and non-standard ports are rejected;
  • loopback, private, link-local, reserved, multicast and metadata IPs are denied;
  • every redirect is resolved and validated again;
  • response MIME type, size, redirect count and time are bounded;
  • scraped HTML is never rendered in reports;
  • the worker runs read-only with dropped Linux capabilities in Compose;
  • production still requires an infrastructure egress firewall and isolated crawler runtime.

Read the complete security model and deployment guide.

Current limitations

  • JavaScript-rendered sites are not yet executed; Playwright must run in a separate disposable sandbox before enabling that path publicly.
  • Reputation coverage is narrow without optional provider credentials. “No match” never means certified safe.
  • Market price comparison, reverse-image search, review manipulation, advanced social analysis and screenshot scanning are not implemented.
  • The bundled registrable-domain fallback covers common suffixes; production should use a maintained Public Suffix List.
  • Saved-site rechecks work, but outbound notifications and rich identity/reputation diffs are not included.
  • High-entropy scan/report IDs are capability links. A public multi-region deployment should add explicit expiring report-access capabilities.
  • A risk score is a point-in-time assessment, not insurance, certification, or a guarantee.

Recommended next work

  1. Run Playwright in disposable jobs with enforced DNS pinning and egress policy.
  2. Add a second independent reputation adapter with health metrics and circuit breakers.
  3. Introduce a versioned Public Suffix List and brand corpus.
  4. Add market-price and image-match providers with source timestamps and false-positive fixtures.
  5. Add retention controls, notification delivery and richer watch-event diffs.
  6. Run Lighthouse, accessibility, load, dependency, container and external penetration tests before public deployment.

ScamShield reports observed evidence and uncertainty. Prefer payment methods with buyer protection, and never treat a low score as a certification.

About

Evidence-first website risk analysis — paste a link and inspect the signals before you buy.

Topics

Resources

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages