For security reviewers

Security, by construction

The security design, threat model, and concrete in-code mitigations. File references point at the actual source so each claim is auditable.

Version 1.0.12 Manifest V3 No remote code Strict CSP

1. Design posture

No remote code

No eval, no new Function, no dynamically loaded or remotely hosted scripts. All code ships inside the signed package.

socket.io-client bundled locally

The Deal Feed compiles socket.io-client into the bundle at build time — not fetched from a CDN at runtime.

MV3 isolation

Manifest V3 service worker with isolated content scripts. No persistent background page; privileged work delegated to short-lived offscreen/hidden contexts.

Local-first data

All config, credentials, and history in chrome.storage.local — no sync, no account. Never uploaded. The only first-party contact is the opt-in, receive-only Deal Feed (§4).

Strict Content Security Policy (extension_pages)

script-src 'self'; object-src 'self';
img-src 'self' data: https://api.qrserver.com https://tg-forwarded-deals.deals.group;
connect-src 'self' https: wss:;
frame-src https: http:;
style-src 'self' 'unsafe-inline'

script-src 'self' means the browser refuses to execute any inline or remote script in extension pages. No eval/unsafe-inline for scripts. Zero runtime npm dependencies in the shipped bundle other than the locally-bundled socket.io-client.

2. Threat model

AssetThreatMitigation
User credentials (Telegram tokens, shortener keys, webhook secrets)Exfiltration via export/share, analytics, or a malicious pageExport/share secret redaction; analytics allowlist + value scrubbing; cookie allowlist
Internal/localhost/cloud-metadata servicesSSRF via user-supplied endpointsisPublicHttpUrl() guard on every endpoint and redirect hop
The extension origin / rendered UIXSS via crafted link text, store responses, or Deal Feed messagesStrict CSP; client-side re-sanitization to an allow-listed tag set; dangerous-scheme blocking
Third-party sites you browseThe mobile-preview DNR rule stripping their framing/CSP during normal browsingDNR rule scoped via initiatorDomains; registered only while preview is open
Stored configurationPoisoning via a malicious import filePer-key shape validation + SSRF check + atomic write with rollback
The runtime message channelSpoofed messages from web pages into the service workerMessage-type validation + sender.id check + payload size caps
Third-party endpoints / local networkSelf-inflicted flood from a many-link conversionOutbound concurrency gate (cap 6) + 429/503 backoff
UsersIDN homograph (phishing lookalike) links getting taggedisSuspiciousIdnHost() rejection
User cookies/sessionLeaking cookies while following redirects or loading feed imagescredentials:'omit' on redirect & feed-image fetches; cookie allowlist for shorteners

3. Concrete mitigations (in code)

SSRF guard — isPublicHttpUrl()

src/utils/url.ts. Rejects any URL that is not routable-public HTTP(S): loopback, link-local, cloud-metadata, RFC1918 private ranges, IPv6 ULA, localhost/.local/.internal, and non-HTTP(S) schemes. Decodes IPv4 literal forms (dotted, hex, octal, inet_aton short) and expands IPv6. Applied to every user-supplied endpoint and every redirect hop.

Cookie allowlist for shorteners

Cookies sent only to a hardcoded affiliate-shortener host allowlist (the Amazon family, amzn.to, flipkart.com, fkrt.it, fkrt.cc, dl.flipkart.com). Every other request uses credentials:'omit'. See src/services/ShortenerService.ts.

Credentialless redirect & feed-image fetches

The redirect resolver issues all fetches with credentials:'omit', so following a link never attaches your cookies to arbitrary hosts. Deal Feed images are likewise fetched with credentials:'omit'.

IDN homograph rejection — isSuspiciousIdnHost()

Flags hosts whose labels punycode to xn--… (e.g. Cyrillic-а flipkаrt.com). Cleaning rules and affiliate templates are not applied to such hosts.

Dangerous-scheme blocking

Anything rendered into an href is constrained to HTTP(S); javascript:, data:, vbscript:, file:, chrome: are blocked from becoming clickable links.

Secret redaction in export/share

exportAll() redacts credential-shaped fields by default unless you choose Include credentials. Single-item community shares always strip secrets. Error messages are scrubbed.

Runtime message validation + sender check + size caps

Inbound messages are validated against known types; a sender.id !== chrome.runtime.id guard rejects messages not from this extension; payload size caps bound accepted data.

Import shape validation + rollback

importAll() performs per-key shape validation, re-runs the SSRF guard on webhook/shortener URLs, and writes inside an atomic try/catch with snapshot rollback. Storage is never clear()-ed first.

Mobile-preview DNR rule scoped to own frames

The single dynamic rule pins initiatorDomains to the extension id and scopes to sub_frame, so it applies only to requests initiated by the extension's own pages. Registered only when you open the preview and removed afterward.

webRequest is read-only

Reads the Location header on cross-origin 3xx redirects so the tracer/resolver can follow the chain. It never modifies traffic; listeners added/removed per hop.

Outbound-fetch concurrency gate

src/utils/netGate.ts. Caps in-flight gated requests at 6 and applies exponential backoff with jitter on 429/503, honoring a numeric Retry-After. All redirect/shortener fetches go through gatedFetch.

4. Deal Feed security

The Deal Feed is the extension's one first-party network feature, designed to be safe by construction:

Opt-in

Nothing connects automatically. You must click Connect (a confirmation prompt). No account, no sign-in.

Receive-only

A Socket.io WSS connection to receive a stream of deals. The client never sends user data beyond a standard WebSocket; the server reports an anonymous online-client count.

No browser cookies

The WebSocket sends no cookies; feed images fetched with credentials:'omit'.

Re-sanitized before render

Every incoming message is re-sanitized into an allow-listed tag subset (sanitizeEditorHtml) before assignment to the DOM. Plain text is HTML-escaped. XSS-safe.

Locally bundled client

socket.io-client compiled into the bundle (no remote script load).

Auto-disconnect

Auto-disconnects after 5 minutes of inactivity; manual Disconnect anytime. Live-only with no stored backlog.

5. Permissions

The extension requests exactly: storage, tabs, scripting, contextMenus, clipboardWrite, notifications, alarms, webNavigation, webRequest, sidePanel, offscreen, declarativeNetRequest, plus host_permissions: <all_urls>. There is no activeTab. The content script over <all_urls> does not read or exfiltrate page content; its optional auto-detect is off by default.

Full permission justifications →

6. Analytics

Delivered to GA4 (www.google-analytics.com/g/collect) only while enabled, with non_personalized_ads:true on every payload. The setting is presented as a pre-enabled toggle in the first-run wizard, so completing onboarding without changing it resolves to on — the Chrome data disclosure marks user-activity analytics as Yes (event counts only). Turn it off any time in Settings → Behavior.

It sends only an allowlisted set of non-personal params plus a random client id and per-session id; a denylist regex drops any URL/email/20+ char token; strings capped at 40 chars. It never sends URLs, domains, tags, tokens, secrets, message bodies, page content, config, user_id, or user_properties — by construction. Events batched (≤25/request) and rate-limited (30/min).

7. Data storage and limits

•

Data lives in chrome.storage.local only (quota ~10 MB). chrome.storage.session holds only transient values. No chrome.storage.sync, no unlimitedStorage.

•

Credentials are stored locally only and never uploaded to any DealsGroup server.

•

History is capped (default 500, configurable 100–5000), oldest pruned. The redirect cache is TTL-bounded (default 24h) with a hard cap of 1000 entries.

8. Responsible disclosure

If you find a security issue, please report it privately before public disclosure. Email [email protected] with the subject line SECURITY: DealsGroup Affiliate Engine.

Please include: the extension version (currently 1.0.12), your Chrome version and OS, a description and reproduction steps, expected vs. actual behavior, and any proof-of-concept. Do not include real credentials. We aim to acknowledge reports promptly and will coordinate a fix and disclosure timeline with you.

Report a vulnerability

9. Verifying these claims yourself

•

Inspect the cited source files — every mitigation maps to a concrete file.

•

Confirm the manifest permissions and CSP in src/manifest.json.

•

Review the SSRF test coverage in test/url.ssrf.test.ts.

•

Project home and contact: deals.group.