Skip to content

Dev to release - #134

Merged
KelvinTegelaar merged 35 commits into
mainfrom
dev
Apr 7, 2026
Merged

KelvinTegelaar merged 35 commits into
mainfrom
dev

Conversation

@KelvinTegelaar

Copy link
Copy Markdown
Contributor

No description provided.

bmsimp and others added 30 commits December 18, 2025 15:01
* Update detection-rules.json

Signed-off-by: Zacgoose <107489668+Zacgoose@users.noreply.github.com>

* Update detection-rules.json

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: John Duprey <jwd@johnwduprey.com>

* Update detection-rules.json

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: John Duprey <jwd@johnwduprey.com>

* Update rules/detection-rules.json

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Zacgoose <107489668+Zacgoose@users.noreply.github.com>

* Update detection-rules.json

Signed-off-by: Zacgoose <107489668+Zacgoose@users.noreply.github.com>

---------

Signed-off-by: Zacgoose <107489668+Zacgoose@users.noreply.github.com>
Signed-off-by: John Duprey <jwd@johnwduprey.com>
Co-authored-by: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com>
Co-authored-by: John Duprey <jwd@johnwduprey.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: John Duprey <jwd@johnwduprey.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: John Duprey <jwd@johnwduprey.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: John Duprey <jwd@johnwduprey.com>
Updated content and detection rules manager scripts to retrieve configuration and branding data via chrome.runtime messaging to the background script, ensuring merged enterprise and local config is used. DetectionRulesManager now accepts a ConfigManager instance for improved config access. Fallbacks to local storage remain for robustness.
…port

Add domain squatting detection with typosquatting, homoglyphs, combosquatting, Levenshtein distance, configurable page blocking, CIPP reporting, webhook integration, and unified URL allowlist configuration
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Zacgoose <107489668+Zacgoose@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Zacgoose <107489668+Zacgoose@users.noreply.github.com>
Introduce supportUrl, privacyPolicyUrl and aboutUrl branding properties across the project. Updates include managed schema, default configs, enterprise policy templates (REG/PS/ADMX/ADML/JSON), options and popup UI/JS, config manager merging logic (including deriving supportUrl from supportEmail when missing), and tests covering branding link behavior. Also removes the legacy companyURL field from many places and updates docs to show the new properties and examples.
Signed-off-by: Zacgoose <107489668+Zacgoose@users.noreply.github.com>
Add support/privacy/about branding URLs
Add `msn.com` and `xbox.com` and `mcas.ms` to Microsoft domain allow-list in detection rules
Signed-off-by: Zacgoose <107489668+Zacgoose@users.noreply.github.com>
Add enterprise webhook policy parity across ADMX, deployment templates and docs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Zacgoose <107489668+Zacgoose@users.noreply.github.com>
Zacgoose and others added 3 commits April 7, 2026 19:42
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Zacgoose <107489668+Zacgoose@users.noreply.github.com>
Firefox changes and feedback changes
Copilot AI review requested due to automatic review settings April 7, 2026 11:47
Signed-off-by: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com>
@KelvinTegelaar
KelvinTegelaar merged commit fa43f0e into main Apr 7, 2026
3 checks passed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR prepares the project for a release by renaming “ProjectX” references to “Check”, expanding branding configuration support, and adding a new domain-squatting detection capability integrated into the background + content-script flow.

Changes:

  • Add domain squatting detection (new module, ruleset config, background/content integration, UI messaging on blocked/warn flows).
  • Update branding model (support/privacy/about URLs, enterprise/local merge behavior) and propagate to popup/options/blocked experiences.
  • Release packaging + docs updates (version bumps, schema/policy templates, documentation restructuring).

Reviewed changes

Copilot reviewed 36 out of 36 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
tests/config-persistence.test.js Adds test coverage for branding-link precedence and mailto derivation.
scripts/modules/domain-squatting-detector.js New detector module (Levenshtein/homoglyph/typosquat/combosquat) + allowlist-domain extraction.
scripts/modules/detection-rules-manager.js Allows using ConfigManager to load merged (enterprise + local) config.
scripts/modules/config-manager.js Updates default URLs, adds domainSquatting defaults, expands branding fields, updates branding merge/derivation.
scripts/content.js Integrates domain-squatting check, refactors indicator evaluation portability, improves blocking/banner DOM creation, adjusts scan timing.
scripts/blocked.js Fixes URL param decoding behavior and adds domain-squatting specific UI/technical-details rendering.
scripts/background.js Instantiates/initializes detector, adds domain-squatting message handler, adds redirect fallback handler, updates threat event enrichment defaults.
rules/detection-rules.json Bumps rules version, expands domain patterns, introduces domain_squatting config + protected domains, refines code-driven indicators.
popup/popup.js Updates branding link behavior (aboutUrl support), removes company-link handling, avoids innerHTML in several places.
popup/popup.html Removes clickable company link in footer.
package.json Renames package and bumps version.
package-lock.json Renames package metadata.
options/options.js Adds domain-squatting toggle, branding URL fields, collapsible config overview UI, more CSP-safe DOM updates, policy reset logic changes.
options/options.html Adds domain-squatting setting + branding URL fields; adds expand/collapse UI; removes company URL field; removes inline script.
options/options.css Adds styling for collapsible config sections and expandable lists.
manifest.json Bumps extension version.
manifest.firefox.json Bumps extension version and adjusts Firefox-specific settings.
LICENSE Renames copyright holder to “Check”.
enterprise/Test-Extension-Policy.ps1 Adds domainSquatting and genericWebhook policy test data; removes companyURL branding field.
enterprise/Remove-Windows-Chrome-and-Edge.ps1 Removes genericWebhook/domainSquatting policy keys; updates branding fields removed/added.
enterprise/README.md Adds webhook documentation link.
enterprise/macos-linux/README.md Documents webhook and domainSquatting policy support; reorganizes deployment notes.
enterprise/macos-linux/edge-managed-policy.json Adds domainSquatting + new branding URL fields.
enterprise/macos-linux/deploy-extension-prefs.sh Adds genericWebhook defaults and updates default rules URL.
enterprise/macos-linux/chrome-managed-policy.json Adds domainSquatting + new branding URL fields.
enterprise/macos-linux/check-extension-config.mobileconfig Adds genericWebhook + domainSquatting defaults; updates rules URL.
enterprise/firefox/policies.json Adds domainSquatting + new branding URL fields; removes companyURL.
enterprise/Deploy-Windows-Chrome-and-Edge.ps1 Adds domainSquattingEnabled and new branding URL fields; removes companyURL.
enterprise/Check-Extension-Policy.reg Adds domainSquatting + genericWebhook policy examples; adds branding URL fields.
enterprise/admx/en-US/Check-Extension.adml Adds ADML strings for generic webhook, domain squatting, and branding URL fields; removes companyURL strings.
enterprise/admx/Check-Extension.admx Adds policies for generic webhook, domain squatting, and branding URL fields; removes companyURL policies.
docs/SUMMARY.md Adds a new “Features” section linking domain squatting docs.
docs/settings/detection-rules.md Documents allowlist dual-use for phishing exclusion + squatting protection.
docs/settings/branding.md Updates branding docs for new link fields; removes companyURL references; formatting improvements.
docs/settings/about.md Refreshes About page content/links and formatting.
docs/README.md Updates marketing/install text and indicates Firefox “Coming Soon”.
docs/firefox-support.md Marks page hidden/noIndex and formatting cleanup.
docs/features/domain-squatting-detection.md Adds feature documentation for domain squatting detection.
docs/deployment/firefox-deployment.md Marks page hidden/noIndex and formatting cleanup.
docs/deployment/chrome-edge-deployment-instructions/windows/manual-deployment.md Adds webhook deployment note.
docs/deployment/chrome-edge-deployment-instructions/README.md Renames page and removes embedded Firefox deployment section.
config/managed_schema.json Removes companyURL; adds branding link fields and domainSquatting schema.
config/branding.json Removes companyURL; adds support/privacy/about URL placeholders.
CHANGELOG.md Updates repository URLs from ProjectX to Check.
AGENTS.md Renames ProjectX guide to Check.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +141 to +145
const rulesDomainSquatting = rulesConfig?.domain_squatting || {};
const runtimeDomainSquatting = runtimeConfig?.domainSquatting || {};

this.enabled = runtimeDomainSquatting.enabled !== false;
this.protectedDomains = rulesDomainSquatting.protected_domains || [];

Copilot AI Apr 7, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

initialize() sets this.enabled solely from runtimeConfig.domainSquatting.enabled and ignores rulesConfig.domain_squatting.enabled. This means a rules file that disables domain squatting (enabled: false) will still be treated as enabled as long as runtime config doesn't explicitly disable it (and your defaults set it to true). Update the merge logic to honor rules first (e.g., runtime.enabled ?? rules.enabled ?? true) so the ruleset can actually disable the feature.

Copilot uses AI. Check for mistakes.
Comment on lines +92 to +107
// Remove regex anchors and escaping
let cleaned = pattern.trim()
.replace(/^\^/, '') // Remove leading ^
.replace(/\$$/, '') // Remove trailing $
.replace(/\\/g, ''); // Remove escape characters

// Try to extract domain from URL pattern
// Pattern formats:
// - https://example.com/...
// - ^https://example\.com$
// - *.example.com
// - example.com

// Extract hostname from URL-like patterns
const urlMatch = cleaned.match(/^(?:https?:\/\/)?([a-zA-Z0-9][\w\-\.]*[a-zA-Z0-9])/);
if (urlMatch) {

Copilot AI Apr 7, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extractDomainsFromAllowlist() is documented as handling regex patterns, but the current extraction regex only matches hostnames that start with an alphanumeric character. Common allowlist regex patterns like ^https:\/\/.*\.example\.com\/.*$ (or patterns starting with ( / .*) won't yield any extracted domain, so those domains won't be protected. Consider handling leading wildcard/regex tokens (e.g., stripping leading (?:\(\?:)?\.?\* / \(.*\) segments) or using a more robust URL/regex hostname extraction strategy so allowlist-derived protection works for typical regex allowlist entries.

Copilot uses AI. Check for mistakes.
Comment on lines +551 to +585
detectCombosquat(testDomain, protectedDomain) {
// Check if protected domain is contained in test domain
if (testDomain.includes(protectedDomain) && testDomain !== protectedDomain) {
const prefix = testDomain.substring(0, testDomain.indexOf(protectedDomain));
const suffix = testDomain.substring(testDomain.indexOf(protectedDomain) + protectedDomain.length);

// Common combosquatting prefixes and suffixes
const commonCombos = [
'secure', 'login', 'account', 'verify', 'support', 'help', 'my',
'auth', 'sso', 'signin', 'app', 'portal', 'online', 'web',
'mobile', 'service', 'official', 'verified', 'safe'
];

const hasCommonCombo = commonCombos.some(combo =>
prefix.includes(combo) || suffix.includes(combo)
);

if (hasCommonCombo) {
return {
technique: 'combosquat',
description: 'Domain adds suspicious prefix/suffix to protected domain',
pattern: 'common_combo',
prefix: prefix,
suffix: suffix,
confidence: 0.9
};
}

// Any prefix/suffix is suspicious but lower confidence
if (prefix || suffix) {
return {
technique: 'combosquat',
description: 'Domain adds prefix/suffix to protected domain',
pattern: 'generic_combo',
prefix: prefix,

Copilot AI Apr 7, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

detectCombosquat() treats any occurrence of protectedDomain as a match (testDomain.includes(protectedDomain)), which will produce false positives for legitimate domains where the protected base is just a common substring (e.g., backoffice.com would match protected base office). Consider restricting combosquatting detection to clearer boundaries (start/end, -/_ separators, or whole-label matching) and/or requiring suspicious prefix/suffix patterns rather than arbitrary substrings.

Copilot uses AI. Check for mistakes.
Comment on lines +336 to +341
// Handle common two-part TLDs like .co.uk, .com.au
if (parts.length >= 3 && ['co', 'com', 'net', 'org', 'gov', 'edu'].includes(parts[parts.length - 2])) {
return parts[parts.length - 3];
}
return parts[parts.length - 2];
}

Copilot AI Apr 7, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extractBaseDomain() has hardcoded handling for a small set of 2-part TLDs and will mis-extract the registrable domain for many common public suffixes (e.g., example.ac.uk returns ac instead of example). This can materially affect squatting detection accuracy and increase false positives/negatives. Consider using a Public Suffix List-based approach (e.g., tldts-style logic) or expanding/centralizing suffix handling so base-domain extraction is correct across TLDs.

Copilot uses AI. Check for mistakes.
Comment thread scripts/content.js
Comment on lines 2067 to 2071
);
const resources = [...source.matchAll(resourceRegex)].map((m) => m[1]);

if (resources.length === 0) return false;
if (resources.length === 0) return true;

Copilot AI Apr 7, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resource_from_domain returns true when no matching resources are found (resources.length === 0). In the ruleset, phi_012_suspicious_resources sets invert: true, so pages with no customcss resources will be treated as suspicious (because true becomes false after invert and triggers). This is a logic inversion bug: when there are no resources of the requested type, the check should return false ("cannot confirm all resources are from allowed domains") so invert doesn't incorrectly flag pages.

Copilot uses AI. Check for mistakes.
Comment thread scripts/blocked.js
Comment on lines +794 to +797
const severityElement = document.getElementById("techSeverity");
const severityMap = { critical: "CRITICAL", high: "HIGH", medium: "MEDIUM", low: "LOW" };
const severityText = severityMap[details.severity] || details.severity.toUpperCase();
setSeverityBadge(severityElement, details.severity, severityText);

Copilot AI Apr 7, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the domain-squatting technical-details path, const severityText = severityMap[details.severity] || details.severity.toUpperCase(); will throw if details.severity is missing/undefined. This can break the blocked page for domain-squatting events that don't provide a severity. Use a safe fallback (e.g., default to 'HIGH'/'UNKNOWN' and guard before calling toUpperCase()).

Copilot uses AI. Check for mistakes.
Comment thread options/options.js
Comment on lines +2746 to +2748
this.elements.companyURL,
this.elements.productName,
this.elements.supportEmail,

Copilot AI Apr 7, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

enableAllPolicyManagedFields() still references this.elements.companyURL (element removed) and does not re-enable the newly added branding fields (supportUrl, privacyPolicyUrl, aboutUrl). After leaving managed mode, those fields may remain disabled/marked as policy-managed. Update allFields to include the new elements and remove the obsolete companyURL reference.

Suggested change
this.elements.companyURL,
this.elements.productName,
this.elements.supportEmail,
this.elements.productName,
this.elements.supportEmail,
this.elements.supportUrl,
this.elements.privacyPolicyUrl,
this.elements.aboutUrl,

Copilot uses AI. Check for mistakes.
Comment thread package.json
@@ -1,6 +1,6 @@
{
"name": "Check",

Copilot AI Apr 7, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The npm package name is set to "Check" (uppercase). npm package names must be lowercase and URL-safe; using an uppercase name will break npm pack/publish and some tooling. Consider using a lowercase name (e.g., "check" or "check-extension") even if this repo isn't intended for publishing.

Suggested change
"name": "Check",
"name": "check",

Copilot uses AI. Check for mistakes.
Comment on lines +8 to +22
export class DomainSquattingDetector {
constructor() {
this.protectedDomains = [];
this.enabled = true;
this.action = 'block';
this.minimumSeverity = 'high';
this.logDetections = true;
this.deviationThreshold = 2; // Maximum Levenshtein distance
this.algorithms = {
levenshtein: true,
homoglyph: true,
typosquat: true,
combosquat: true
};

Copilot AI Apr 7, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR introduces a large, security-sensitive DomainSquattingDetector module (homoglyphs/Levenshtein/typosquat/combosquat) but adds no unit tests for it. Given the high risk of false positives/negatives, add focused tests covering: base-domain extraction (incl. multi-part TLDs), allowlist-domain extraction, combosquat boundary cases, and rule/runtime precedence (enabled/action/severity).

Copilot uses AI. Check for mistakes.
Comment thread options/options.js
Comment on lines +3773 to +3819
// Minimal config summary: just show code-driven indicator count and key settings
function renderConfigSummary(config) {
const codeDrivenDiv = document.getElementById('codeDrivenIndicators');
const keySettingsUl = document.getElementById('configKeySettings');
if (!config || !config.phishing_indicators) return;
// Show only code-driven indicator count
const codeDrivenCount = config.phishing_indicators.filter(r => r.code_driven).length;
const codeItem = document.createElement('div');
codeItem.className = 'config-item';
const codeLabel = document.createElement('strong');
codeLabel.textContent = 'Code-Driven Indicators:';
const codeValue = document.createElement('span');
codeValue.className = 'config-value';
codeValue.textContent = String(codeDrivenCount);
codeItem.appendChild(codeLabel);
codeItem.appendChild(document.createTextNode(' '));
codeItem.appendChild(codeValue);
codeDrivenDiv.replaceChildren(codeItem);
// Show some key settings
keySettingsUl.replaceChildren();
const appendSetting = (label, value) => {
const li = document.createElement('li');
const strong = document.createElement('strong');
strong.textContent = `${label}:`;
li.appendChild(strong);
li.appendChild(document.createTextNode(` ${value}`));
keySettingsUl.appendChild(li);
};
if (config.version) appendSetting('Rules Version', config.version);
if (config.lastUpdated) appendSetting('Last Updated', config.lastUpdated);
if (config.detection_settings && config.detection_settings.block_threshold !== undefined) {
appendSetting('Block Threshold', config.detection_settings.block_threshold);
}
if (config.detection_settings && config.detection_settings.warn_threshold !== undefined) {
appendSetting('Warn Threshold', config.detection_settings.warn_threshold);
}
}

// Patch into config loading logic
(function() {
const origShowConfig = window.showConfigDisplay;
window.showConfigDisplay = function(config) {
if (typeof origShowConfig === 'function') origShowConfig(config);
renderConfigSummary(config);
document.getElementById('configSummary').style.display = '';
};
})();

Copilot AI Apr 7, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The global renderConfigSummary + window.showConfigDisplay patch appears to be dead code: there is no other reference to showConfigDisplay in this file, so the wrapper never runs and the summary UI likely never updates. Either wire this into the existing config rendering flow (e.g., call renderConfigSummary(this.currentConfigData) after loading) or remove it to avoid confusion.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants