Skip to content

Repository files navigation

XAI JS Detector

A Chrome extension that detects and blocks malicious JavaScript in real time using an Explainable Boosting Machine (EBM) — an intrinsically interpretable ML model that produces human-readable explanations alongside every decision.

Live backend: https://xai-malwarejs-backend.onrender.com


How it works

Every script and network request intercepted by the extension is sent to a two-stage pipeline:

[Web Page JS]
      │
      ▼
[injected_hook.js]   — overrides eval(), Function(), fetch(), XHR, setTimeout in page context
      │  window.postMessage()
      ▼
[interceptor.js]     — content script, relays messages out of page context
      │  chrome.runtime.sendMessage()
      ▼
[service_worker.js]  — applies local heuristic pre-filter; sends to backend if needed
      │  POST /analyze
      ▼
[Flask backend]      — EBM classifier → local explanation (both in < 10 ms)
      │  { decision, score, top_features, explanation }
      ▼
[Popup / banner]     — shows verdict, risk score, and top contributing signals

Stage 1 — Fast pre-filter: Scripts with no suspicious signals are allowed instantly without hitting the backend.

Stage 2 — EBM classifier: The remaining scripts are scored by an Explainable Boosting Machine. EBM is intrinsically interpretable — it produces exact feature contributions (not post-hoc approximations) with negligible extra cost.

Network requests (fetch / XHR) use a separate rule-based path that checks for credential exfiltration patterns (password fields, auth tokens, cookie values in cross-origin POST bodies).


Features

Feature Description
Real-time blocking Intercepts eval, Function(), fetch, XHR, setTimeout before execution
XAI explanations EBM feature contributions shown per detection — no black box
Heuristic fallback Works offline; backend is optional
Network analysis Detects credential exfiltration in outbound requests
Live popup UI Risk gauge, top signals, full feature grid, intercept feed
Configurable Threshold slider, block vs. flag mode, notifications
Export Download full intercept log as JSON

Project structure

XAI-MalwareJs/
│
├── extension/                   ← Load this folder into Chrome
│   ├── manifest.json            ← Manifest V3
│   ├── icons/
│   ├── content/
│   │   ├── injected_hook.js     ← Runs in page context (MAIN world)
│   │   └── interceptor.js       ← Runs in extension context; relays messages
│   ├── background/
│   │   └── service_worker.js    ← Heuristic scoring + backend calls + log storage
│   └── popup/                   ← Built output of ui/ — do not edit directly
│
├── ui/                          ← Popup source (React + TypeScript + Tailwind)
│   ├── src/
│   │   ├── App.tsx
│   │   ├── components/          ← StatusHero, Feed, DetailPanel, Settings, …
│   │   └── lib/bridge.ts        ← chrome.runtime messaging (+ mock for npm run dev)
│   └── vite.config.ts
│
├── backend/
│   ├── app.py                   ← Flask API (EBM classifier + local explanation)
│   ├── requirements.txt
│   ├── XAI_New_2026.ipynb       ← Model training notebook
│   └── models/
│       ├── ebm_model.pkl        ← Trained EBM (interpret library)
│       └── feature_columns.pkl  ← Feature order used at training time
│
└── make_icons.py                ← One-time icon generation

Quick start

1. Load the extension

The extension works immediately with the hosted backend — no local setup required.

  1. Open Chrome → chrome://extensions
  2. Enable Developer mode (top-right toggle)
  3. Click Load unpacked → select the extension/ folder
  4. The shield icon appears in your toolbar

2. (Optional) Run the backend locally

The extension works without the backend. put https://xai-malwarejs-backend.onrender.com into .env file
To get proper ML + SHAP explanations:

cd backend
pip install -r requirements.txt
python app.py

Then set the backend URL in the extension Settings to http://localhost:5000.

3. (Optional) Rebuild the popup UI

cd ui
npm install
npm run build      # outputs to extension/popup/

For fast iteration outside Chrome:

npm run dev        # serves popup with mock data at http://localhost:5173/popup.html

Backend API

Base URL: https://xai-malwarejs-backend.onrender.com

GET /health

{ "status": "ok", "model": true }

POST /analyze

Accepts a feature payload extracted by the extension. Returns a decision, risk score, and explanation.

curl -X POST https://xai-malwarejs-backend.onrender.com/analyze \
  -H "Content-Type: application/json" \
  -d '{
    "source": "eval",
    "url": "https://example.com",
    "eval_count": 3,
    "entropy": 6.8,
    "atob_count": 1,
    "fromcharcode_count": 5,
    "hex_escape_count": 45,
    "code_length": 1200,
    "line_count": 3
  }'

Response:

{
  "decision": "BLOCK",
  "score": 0.91,
  "top_features": [["eval() calls", 3], ["Code entropy (obfuscation signal)", 6.8]],
  "explanation": "Risk score: 91%. Primary signals: eval() calls, Code entropy. Script classified as malicious.",
  "stage": "ebm-classifier",
  "classify_ms": 4.2
}

GET /logs

Returns the last N intercepts (default 100). Add ?limit=N to change.

GET /stats

{ "total": 412, "blocked": 38, "allowed": 374, "block_rate": 0.092, "avg_score": 0.14 }

POST /feedback

Submit a correction label for a logged intercept.


EBM features

The model uses 10 features extracted from each intercepted script:

Feature Description
length Total character count of the script
num_lines Number of lines
entropy Shannon entropy — high values indicate obfuscation
eval_count eval() calls
function_count new Function() constructor calls
atob_count atob() base64-decode calls
fromcharcode_count String.fromCharCode() calls
hex_escape_count \x41-style hex escape sequences
long_var_names Long identifier / string patterns (obfuscation proxy)
url_count Embedded URLs in code

The model was trained and exported in backend/XAI_New_2026.ipynb.


Retraining the model

Open backend/XAI_New_2026.ipynb in Jupyter and run all cells. The notebook trains an EBM on the labelled dataset and exports ebm_model.pkl and feature_columns.pkl to backend/models/.


Troubleshooting

Extension not intercepting anything

  • Go to chrome://extensions → check for errors on the XAI card
  • Open DevTools on any page → Console → look for [XAI Hook] Installed
  • Some pages with strict CSP block script injection — the test page has no CSP

Popup shows "heuristic mode"

  • This is normal when the backend is cold-starting on Render (free tier sleeps after inactivity) — it wakes up within ~30 seconds
  • Or set a local backend URL in Settings

Too many false positives

  • Raise the detection threshold in Settings (e.g. 70%)
  • Switch to "Flag" mode (observe without blocking)

Contributing

Contributions are welcome. Please open an issue before submitting a pull request for significant changes.

  1. Fork the repo
  2. Create a feature branch (git checkout -b feature/your-feature)
  3. Commit your changes
  4. Push and open a pull request

License

MIT — see LICENSE.

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages