Metadata-Version: 2.4
Name: cybersecurity-browser-extension-agent
Version: 1.1.2
Summary: Local phishing-detection agent for the Cybersecurity Browser Extension (Chrome)
Author: Yap Zheng Xian
License-Expression: MIT
Project-URL: Homepage, https://github.com/zxianyap142857/cybersecurity-browser-extension
Project-URL: Privacy policy, https://zxianyap142857.github.io/Cybersecurity-Browser-Extension/privacy-policy.html
Keywords: phishing,security,onnx,federated-learning,browser-extension
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: End Users/Desktop
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: MacOS
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Security
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: flask>=3.0
Requires-Dist: flask-cors>=4.0
Requires-Dist: waitress>=3.0
Requires-Dist: onnxruntime>=1.17
Requires-Dist: tokenizers>=0.15
Requires-Dist: numpy>=1.24
Requires-Dist: pandas>=2.0
Requires-Dist: scikit-learn==1.7.2
Requires-Dist: lightgbm>=4.0
Requires-Dist: joblib>=1.3
Provides-Extra: tray
Requires-Dist: pystray>=0.19; extra == "tray"
Requires-Dist: pillow>=10.0; extra == "tray"
Provides-Extra: train
Requires-Dist: torch>=2.2; extra == "train"
Requires-Dist: transformers<6,>=4.40; extra == "train"
Requires-Dist: peft<1,>=0.10; extra == "train"
Requires-Dist: safetensors>=0.4; extra == "train"
Dynamic: license-file

# Cybersecurity Browser Extension Agent

The local detection service for the **Cybersecurity Browser Extension**. It runs the
three-model phishing ensemble on your own machine and answers the extension on
`http://127.0.0.1:5000`.

Nothing about the pages you visit is sent anywhere. The extension parses each page
in the tab and sends the agent a URL, a stripped text summary and 43 numeric
features; the agent replies with a verdict. Raw HTML never leaves the browser, and
the agent only ever accepts connections from your own computer.

```
browser tab ──► extension ──► 127.0.0.1:5000/predict_ensemble
                                 ├─ URL   DistilBERT   (ONNX)
                                 ├─ HTML  MobileBERT   (ONNX)
                                 └─ meta  LightGBM     43 features
                                 └─ weighted vote → legitimate / suspicious / phishing
```

## Requirements

- Python 3.10 or newer
- ~1 GB of disk: ~400 MB for the models, the rest for the runtime
- Windows, macOS or Linux — no admin rights needed, everything installs per-user

There is no GPU requirement. A page takes roughly 150 ms on a laptop CPU.

## Install

```bash
python -m pip install "cybersecurity-browser-extension-agent[tray]"
```

`[tray]` adds the system-tray icon (pystray, pillow); leave it off for a headless
machine. The command it installs is `cyberext`. Optional on-device training:

```bash
python -m pip install "cybersecurity-browser-extension-agent[train]"   # torch, transformers, peft
```

Use the same Python for both — the training add-on has to be installed next to the
agent it extends. From a source checkout, `python -m pip install ".[tray]"` in the
`agent` folder does the same.

Upgrading from the pre-rename package (`phishguard-agent`, command `phishguard`):
uninstall it first (`python -m pip uninstall phishguard-agent`), then install this one.
The existing `~/.phishguard` folder — models, training weights, reports, consent — is
moved to `~/.cyberext` on first start, and `cyberext autostart enable` /
`cyberext shortcut create` replace the old login entry and shortcuts.

`[train]` pulls in PyTorch (~1 GB). Skip it unless you intend to contribute model
updates — detection does not need it.

## First run

```bash
cyberext start
```

No configuration is needed. Models come from the project's model service
(`fl-api` on Cloud Run), which hands the agent short-lived signed download links;
the storage bucket itself stays private, and no credentials are ever stored on
your machine.

To point the agent somewhere else (a test server, say), `cyberext configure
--fl-server-url URL` writes `~/.cyberext/config.json`; `--fl-server-url default`
returns to the built-in service. Environment variables (`FL_SERVER_URL`,
`FL_API_KEY`, `CYBEREXT_PORT`, `CYBEREXT_UPDATE_HOURS`) override the file when
set, but a shell variable is not visible to an agent started at login — anything
the agent needs unattended belongs in the config file.

On the first start the agent downloads the current model version (~375 MB), checks
each file against the sha256 in the manifest, and only then makes that version
active. An interrupted download can never leave a half-swapped model in use.

Then load the extension and set **Backend → Local (Dev)** in its sidebar.

## Commands

| Command | What it does |
|---|---|
| `cyberext start` | run the agent (tray icon if `[tray]` is installed) |
| `cyberext start --no-tray` | run it headless in the terminal |
| `cyberext status` | is it running, which model version, updater progress |
| `cyberext update [--force]` | check for new models now |
| `cyberext where` | print the paths it uses |
| `cyberext configure ...` | store settings for unattended start |
| `cyberext autostart enable\|disable\|status` | run at login |
| `cyberext shortcut create\|remove\|status` | desktop / launcher shortcut |
| `cyberext fetch-train-weights [--model M]` | PyTorch weights for on-device training (`[train]` extra) |

`configure` accepts `--fl-server-url`, `--fl-api-key`, `--port`, `--update-hours`;
the value `default` clears a setting (an empty `""` works too, except in Windows
PowerShell 5.1, which silently drops empty arguments). Leave the port at 5000 — that is the only port
the extension connects to.

### Start at login

```bash
cyberext autostart enable
```

Per-user, no services and no admin rights — and `disable` removes exactly what
`enable` created:

| OS | What it writes |
|---|---|
| Windows | `%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\cyberext-agent.cmd` (launches `pythonw.exe`, no console window) |
| macOS | `~/Library/LaunchAgents/com.cyberext.agent.plist` (loaded with `launchctl`) |
| Linux | `$XDG_CONFIG_HOME/autostart/cyberext-agent.desktop` |

It starts **with** the tray icon where one is available, falling back to headless
where it is not: a background process you cannot see or quit is worse than no icon.

### Desktop shortcut

```bash
cyberext shortcut create
```

Starts the agent with a double-click, no terminal:

| OS | What it creates |
|---|---|
| Windows | `Cybersecurity Browser Extension Agent.lnk` on the Desktop and in the Start Menu, running `pythonw.exe` (no console window) |
| macOS | `~/Applications/Cybersecurity Browser Extension Agent.app` (menu-bar icon only, no Dock tile) + a link on the Desktop |
| Linux | `cyberext-agent.desktop` in the application launcher, and on the Desktop if there is one |

Opening the shortcut while the agent is already running opens its status page
(`http://127.0.0.1:5000/`) instead of starting a second copy. `shortcut remove` checks
each file is one it made before deleting it, so a same-named shortcut of your own is
left alone.

## Tray menu

Live status (model version, or download progress), the port it is listening on, a
manual update check, the *Contribute to model improvement* switch, shortcuts to the
status page and the data folder, and Quit.

An update-check failure while models are installed shows
`Models 1.1.0 ready  (update check failed)` — detection still works, and the menu
says so rather than implying an outage.

## HTTP API

Loopback only; every request is verified to come from `127.0.0.1` before it is
routed, so a misconfigured proxy or a host-header trick cannot reach it. On Windows the
port is also held exclusively, so no other program can bind beside the agent and
intercept what the extension sends. The routes
match the cloud predict-service exactly, so the extension needs no changes.

| Route | Purpose |
|---|---|
| `GET /` | human-readable status page (refreshes every 5 s) |
| `GET /health` | uptime, `models_ready`, `model_version`, `training_available` |
| `GET /ensemble_status` | which model files are present, updater state |
| `POST /predict_ensemble` | the full three-branch verdict |
| `POST /predict`, `POST /batch_predict` | URL-only classification (link scanning) |
| `GET /reports`, `POST /report`, `/report/update`, `/report/delete` | your local corrections |
| `POST /model/update`, `GET /model/update_status` | model download |
| `POST /fusion/report` | scan-panel correction (scores + label; uploaded only with consent) |
| `GET/POST /fl/consent` | device-owner consent for contributing (+ pending correction count) |
| `POST /fl_train`, `GET /fl_status` | local training round (needs `[train]` + consent) |

## Where your data lives

Everything is under `~/.cyberext` (override with `CYBEREXT_HOME`) — uninstalling
is a delete:

```
models/<version>/     the active and previous model versions
models/current        which version is in use
config.json           settings from `cyberext configure`
reports.json          your corrections; kept locally, never uploaded as they are
contribute.flag       present only if you turned on training consent
agent.log
```

## Contributing to model improvement (opt-in)

Off by default. Switch it on from the extension's **Federated Learning** page or the
tray menu (both edit `contribute.flag`). While it is on, the agent sends — anonymously,
with no URL, page content, or device/account ID:

| What | When |
|---|---|
| a **scan correction**: the three branch scores + the right label | each time you flag a wrong verdict on the Page Scan panel |
| a **training update**: the LoRA adapter from a local round (~3 MB, safetensors) plus sample count, base version and update norm | after a training round you start |

On-device training needs the extra and the base weights:

```bash
python -m pip install "cybersecurity-browser-extension-agent[train]"
cyberext fetch-train-weights            # ~466 MB; or --model distilbert
```

A round needs **at least 32 reported URLs** (the model service enforces the same
floor), and the adapter's total change is **clipped** to a fixed norm before upload.
Both reduce how much an update can reveal about the reports it came from; neither is a
formal privacy guarantee. HTML-branch training needs reports with page text, which the
Report page does not collect yet, so only the URL branch (DistilBERT) trains today.

Consent is separate from anything administrative: it authorises training on *your*
data on *your* machine. Combining updates and publishing a new model version to
everyone is an administrator's decision, made in the cloud. Adapters trained here are
never loaded locally — the fleet converges through published versions, otherwise every
training device drifts onto private weights.

## Troubleshooting

**"model server refused the request (HTTP 403)"** — the agent was pointed away from
the built-in model service (or at an empty URL, which means "read the private bucket
directly"). Run `cyberext configure --fl-server-url default` and restart it.

**"model server unreachable"** — no internet, or the model service is down. Detection
keeps working with the models already installed; the tray shows
`Models X ready  (update check failed)` until the next successful check.

**"models_not_ready" from the extension** — the first download has not finished.
`cyberext status` shows the percentage.

**The extension says the agent is not running, but it is** — check the port. The
extension only talks to `127.0.0.1:5000`; the status page and tray menu show which port
the agent is on. If it is anything else, `cyberext configure --port 5000` and restart it.

**Port 5000 is taken** — the agent refuses to start rather than share the port (the tray
icon turns grey and says *not running: port in use*). Find and stop whatever holds it (on Windows:
`netstat -ano | findstr :5000`). `--port` exists for testing; the extension cannot follow
the agent to another port.

**The tray icon does not appear** — headless Linux, Wayland without an AppIndicator,
or `[tray]` not installed. The agent still runs; the message says so and it falls
back to headless.

**Windows: a model update seems stuck** — Windows locks open ONNX files. The agent
releases its sessions before swapping files; if you edited the model folder by hand
while the agent was running, stop it and start again.

## Uninstall

```bash
cyberext autostart disable
cyberext shortcut remove
python -m pip uninstall cybersecurity-browser-extension-agent
```

Then delete `~/.cyberext` if you also want the downloaded models gone.
