CTMonitor Extension Story
About the Project
CTMonitor started from a simple question: can a browser extension warn about suspicious domains fast enough to matter, without sending browsing data to a cloud service first? I wanted to build something that felt practical for real users, but also interesting from a research point of view. That led me toward a local-first browser extension that scores domains on navigation, explains why a page looks risky, and gives the user immediate feedback through badges, banners, popups, and a report view.
This story focuses on the extension itself. The extension is the part that a user actually touches first, so I treated it like the front line of the system: lightweight, private, explainable, and usable even when a backend is unavailable.
What Inspired Me
The main inspiration was the gap between security research and daily browser behavior. A lot of phishing detection systems are impressive in a paper or on a server, but the user still has to wait, trust a remote service, or install something heavy. I wanted the opposite: a small extension that reacts immediately, stays on the machine, and makes the reasoning visible.
I was also motivated by the idea that browser extensions can be more than UI wrappers. They can be decision systems. They can inspect a navigation event, evaluate the domain, and intervene before a user submits credentials. That made the extension a good place to combine research ideas with a real deployment surface.
What I Learned
I learned how constrained a Manifest V3 extension really is, and that constraint was useful. The service worker can be short-lived, content scripts have to be careful, and storage has to be simple. I learned that the extension environment pushes you toward small, deterministic, explainable logic instead of heavy server-side machinery.
I also learned that security software needs to be transparent. A score is not enough. Users need a reason, a tier, and a path to investigate. That is why the extension shows a local report page, weighted detector contributions, and a BLOCK interstitial instead of silently hiding information.
From an engineering point of view, I learned that local-first design is not just a privacy choice; it is also a resilience choice. If the backend is missing or unavailable, the extension still works because the core verdict is computed locally.
How I Built It
The extension is organized around a few browser-native pieces:
Background service worker
- Listens for navigation events.
- Extracts the hostname.
- Computes a local verdict.
- Stores the result in
chrome.storage. - Triggers notifications and badge updates.
Local detector engine
- Runs in plain JavaScript.
- Produces a risk score from several independent signals.
- Works without a backend.
Content script
- Injects a banner on BLOCK or WARN pages.
- Gives the user quick context and an escape route.
Popup and report views
- Show the score, tier, reasoning, and contributions.
- Make the result explainable rather than opaque.
Settings and interstitials
- Let the user toggle backend enrichment.
- Keep privacy-first behavior on by default.
- Provide a safety stop before a risky page fully loads.
The overall build philosophy was to keep the extension useful without requiring a backend. That shaped almost every design choice.
Mathematical and Detection Approach
The extension uses a small ensemble of heuristic signals rather than a single black-box model. Each detector produces a score in the interval \( [0, 1] \), where larger values mean higher suspicion.
If detector \( i \) produces score \( s_i \) with confidence \( c_i \), the extension combines them into a weighted risk estimate:
\[ R = \frac{\sum_i s_i c_i}{\sum_i c_i} \]
This is simple on purpose. It keeps the score stable, explainable, and cheap to compute inside the browser.
The extension then maps the final risk to a tier:
\[ \text{tier} = \begin{cases} \text{BLOCK}, & R \ge 0.85 \ \text{WARN}, & R \ge 0.60 \ \text{WATCH}, & R \ge 0.35 \ \text{SAFE}, & \text{otherwise} \end{cases} \]
That tiering matters because the extension is not just classifying a domain; it is deciding what kind of intervention is appropriate.
Signals Used
The extension’s local engine looks at several kinds of signals:
- Brand similarity: how close the domain is to a known brand string.
- Homograph risk: whether the hostname looks like an IDN or confusable variant.
- Keyword/TLD patterns: whether suspicious words appear in combination with risky top-level domains.
- Structural risk: depth of subdomains, hyphen usage, digit density, and label length.
- Trusted-domain damping: trusted domains are reduced in risk unless other signals are strong.
A good way to think about this is that the extension is not asking one model to do everything. It is asking several small tests to agree. That makes the result easier to defend.
Why This Approach Works in an Extension
Browser code has to be fast and predictable. A more elaborate ML stack would be harder to ship in an extension-only mode, harder to explain, and more likely to fail under MV3 restrictions. The heuristic ensemble fits the environment:
- It is fast enough to run on navigation.
- It does not depend on GPU, Python, or remote inference.
- It produces understandable reasons.
- It can fail gracefully and still keep the browser usable.
Challenges I Faced
The first challenge was the extension lifecycle itself. The service worker can be restarted, so I had to make storage and state handling simple and resilient.
The second challenge was avoiding false confidence. A security extension should not pretend to know more than it does. That is why I added explicit confidence, explainability, and conservative defaults for private or internal hosts.
The third challenge was making the UI feel like a security tool rather than a generic popup. The extension needed to be immediate, calm, and informative. The report view, contribution summaries, and interstitial were all added to give the user context without overwhelming them.
The fourth challenge was deciding what belongs in the extension and what belongs in a backend. I learned that the extension should own the critical path: the first verdict, the warning, and the user-facing explanation. Anything extra should be optional.
What I Would Improve Next
If I continued this project, I would focus on three things:
- Better calibration with labeled phishing and benign datasets.
- A more formal evaluation of false positives and false negatives.
- A stronger policy/settings page for enterprise and competition deployment.
Closing Note
CTMonitor taught me that good security tooling is not only about prediction accuracy. It is also about timing, explanation, and trust. The extension is designed to make a decision quickly, explain that decision clearly, and do it without handing control of the whole experience to a server.
Built With
- chrome
- css
- html
- javascript
- manifest
Log in or sign up for Devpost to join the conversation.