Is uTab - Unlimited Custom Dashboard safe?
uTab routes every new-tab search through search.utab.io with a persistent per-user id before redirecting to Bing.
Each query typed into the new-tab search box is sent to search.utab.io tagged with a persistent per-user UUID and the extension's runtime id, then forwarded on to Bing. The service worker also fetches a remote config from utab.io/api/ every 15 minutes, and that config can override where searches are sent. Separately, the URLs of your bookmarks and pages saved via the 'Save to uTab' menu are sent to the third-party screenshot service sshot.org to generate thumbnail previews.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Bookmark URLs sent to sshot.org previews
Code analysis shows that saving a page or link to uTab, or uTab preparing bookmark-folder previews, sends the saved URL to https://sshot.org in the url parameter, with a Basic authorization header using a bundled credential, redacted below.
You save a page or link to uTab, or ask uTab to prepare previews for a bookmark folder.
The extension sends the saved page URL to sshot.org so that service can generate a thumbnail preview.
| Authorization | Basic <redacted> |
| Field | Value | Why it matters | |
|---|---|---|---|
Saved page URL | https://example.com/private/roadmap?ticket=INC-4821 | The exact page you saved is sent to the screenshot service, including any path and query string in that address. | |
Preview dimensions | width=200&height=112&zoom=0.15 | These values tell the service what size thumbnail to render for the saved page. | |
Bundled service credential | Basic <redacted> | The extension includes a credential for the screenshot service in its shipped code. |
| When | You did | Extension did |
|---|---|---|
| same action | user You choose Save to uTab for the current page or link. | extension The extension stores that URL and immediately requests a preview from sshot.org. |
| per matching bookmark | user You add or edit a folder that contains saved bookmarks. | extension The extension requests previews for bookmark entries whose preview is still marked as loading. |
Preview generation sends bookmark URLs to sshot.org
FOLDER_EDIT: function(t, e) {
t.commit("FOLDER_EDIT", e), chrome.runtime.sendMessage({
action: "getFolderPreviews",
folder: e
}), chrome.runtime.sendMessage({
action: "update_context_menu"
});
},
FOLDER_ADD: function(t, e) {
e.bookmarks.length > 0 && (e.empty = !1), t.commit("FOLDER_ADD", e), chrome.runtime.sendMessage({
action: "getFolderPreviews",
folder: e
}, (function() {
chrome.runtime.lastError;
})), chrome.runtime.sendMessage({
action: "update_context_menu"
}, (function() {
chrome.runtime.lastError;
})), 1 == t.state.storage.settings.folders.length && t.commit("FOLDER_SELECT", e);
}{
key: "createContextMenu",
value: function() {
var t = this;
chrome.contextMenus.removeAll((function() {
if (!a.a.getters.isNoFolders) {
var e = null;
a.a.state.storage.settings.folders && a.a.state.storage.settings.folders.length > 1 && (e = "parentDropDown",
chrome.contextMenus.create({
title: "Save to uTab",
id: e,
contexts: [ "page", "link" ]
}, (function() {
chrome.runtime.lastError;
})));
for (var n = 0; n < a.a.state.storage.settings.folders.length; n++) {
var r = a.a.state.storage.settings.folders[n], o = 'Save to "' + r.name + '"';
1 == a.a.state.storage.settings.folders.length && (o = "Save to uTab"), chrome.contextMenus.create({
title: o,
id: r.id,
parentId: e,
contexts: [ "page", "link" ]
}, (function() {
chrome.runtime.lastError;
}));
}
chrome.contextMenus.onClicked.addListener((function(e, n) {
var r = a.a.state.storage.settings.folders.find((function(t) {
return t.id === e.menuItemId;
}));
if (r) {
var o = {
id: Object(u.b)(),
_id: Object(u.b)(),
title: n.title,
url: n.url,
icon: n.favIconUrl || "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAB3UlEQVQ4T6WTP2hTURjFz7nP2EpxK0pBEFwcnDu3ZMiQWSKK0CQmmgSHVgdBUPEPoqBYHJLQvuZPEZSAq2CGqoOLLi4ijrqIXcVom+Qeua95+VONS+/0OJfvd893vu8RezzcXX92cXEm8nPrqYRZSQfcPclfJN63pyZOP1le/jZcMwJInS8sqWvvC4iQsBA2BbYBHQk4QJueuVJdKT4KIX2AK7Zd+xCAJXEzHoveTSQS3WTm4rzUeTX0qoxnLoeQAOBsez+2vgKiJ56oVEqfnZ7KFB5Y2DMQZnbZbncOTh517QSAVDb/2lrNkbhe88u3nZbMFmZl7btxGRvDN9XV0nwAWEjnWjSYiMei+53tHnROVsUe4JiAyREXZKvml6Z2AOdylsD32lp5xGpYkMzkn0k6NQBoG2CkvlY2fYBLeeiFLsEvoNbjseidZvPtdEfbSyCmIbwE9FjA4QEgnWuBCGa++3g0CxW/uB7qjUbDe9HccA5+91sIQ/xnYORK3S9dGLSTuybh1kiIQ2Pc14eQPoAPBvpU9csbTk+n88e71EcCdmSMQeqDRdrJwuBkfbX83H32bF+VcMPd/LVIfXvZ/CVY3XOrDKJDYBOCAXFIgkt8/CqHkD39TOO27n/6HyyR4xF0kx9xAAAAAElFTkSuQmCC",
preview: "load"
};
a.a.commit("BOOKMARK_MANAGER_ADD", {
item: o,
folder: r
}), a.a.dispatch("FOLDER_BOOKMARK_ADD", {
item: o,
folder: r
}), t.getPreview(o.url).then((function(t) {
o.preview = t, a.a.commit("FOLDER_BOOKMARK_PREVIEW_SET", {
folder: r,
bookmark: o
});
}));
}
}));
}
}));
}
}{
key: "getPreview",
value: function(e) {
return new Promise((function(n, r) {
var o = new Headers;
o.set("Authorization", "Basic " + btoa("user:<redacted>")), fetch("https://sshot.org?url=" + encodeURIComponent(e) + "&width=200&height=112&zoom=0.15&clipRect=0%2C0%2C200%2C112", {
method: "get",
headers: o,
responseType: "arraybuffer"
}).then((function(t) {
return t.arrayBuffer();
})).then((function(e) {
n("data:image/png;base64," + t.from(e, "binary").toString("base64"));
})).catch((function(t) {
n(null);
})).finally((function() {
n(null);
}));
}));
}
}{
key: "getFolderPreviews",
value: function(t) {
var e = this, n = a.a.state.storage.settings.folders.find((function(e) {
return e.id == t.id;
}));
n.bookmarks.forEach((function(t, r) {
"gap" != t.type && "load" == t.preview && e.getPreview(t.url).then((function(e) {
t.preview = e, a.a.commit("FOLDER_BOOKMARK_PREVIEW_SET", {
folder: n,
bookmark: t
});
}));
}));
}
}- sshot.org
Receives each saved page or bookmark URL and returns a thumbnail image for uTab previews.
Remote config can change new-tab searches
We observed the extension request https://utab.io/api/ during dynamic analysis.
Source code stores that JSON as config; searching from the new-tab page replaces the built-in search URL with config.searchTemplate if present.
You search from the uTab new-tab page after the extension has refreshed its configuration.
The extension can build the destination URL from a template returned by utab.io instead of its built-in search URL.
| Field | Value | Why it matters | |
|---|---|---|---|
Search query | weather tomorrow | Your typed search terms are inserted into the selected destination URL. | |
Server-supplied template | https://search.utab.io/search/?q={KEYWORD} | A value from the remote configuration can decide which site receives your search. | |
Extension user ID | f4b1d629-8d7a-4d6f-9f2c-58b0c6d7e0a2 | The built-in search URL includes an extension-generated identifier alongside the query. |
The extension refreshes the remote configuration on startup and then schedules another refresh roughly every 15 minutes.
Config refresh and search URL replacement in the service worker
new (i()((function t() {
var e = this;
r()(this, t), this.config = null, this.bookmarkPreviewTabId = null, this.bookmarkPreviewTabOpenerId = null,
this.searchCount = 0, this.fetchSlidersDate = null, this.updateSliderDate = Date.now(),
chrome.runtime.setUninstallURL("https://utab.io/uninstall.html", (function() {})),
Object(a.b)().then((function() {
e.onStorageLoaded();
})), chrome.runtime.onInstalled.addListener((function(t) {
"update" == t.reason && setTimeout((function() {
null == a.a.state.storage.settings.background && a.a.dispatch("SET_BACKGROUND_APP", {
type: "default",
index: 3
});
}), 1e3), fetch("https://utab.io/beg/?y=" + t.reason).then((function(t) {
return t.json();
})).then((function(n) {
e.newFeaturesReply(t.reason, n);
}));
})), this.initListeners(), this.getConfig(), setInterval((function() {
e.getConfig();
}), 9e5);
}){
key: "getConfig",
value: function() {
var t = this;
Date.now() - a.a.state.storage.user.fetchConfigDate > 9e5 && fetch("https://utab.io/api/").then((function(t) {
return t.json();
})).then((function(e) {
a.a.commit("SET_FETCH_CONFIG_DATE", Date.now()), t.config = e;
})).catch((function(t) {}));
}
}case "search":
var o = "https://search.utab.io/search/?id=".concat(chrome.runtime.id, "&source=newtab&q=").concat(encodeURIComponent(e.query), "&uid=").concat(a.a.state.storage.user.id, "&se=") + "bing";
t.config && t.config.searchTemplate && (o = t.config.searchTemplate.replace("{KEYWORD}", e.query)),
chrome.tabs.update(null, {
url: o
});
break;- utab.io
Provides the remote configuration fetched by the extension.
- search.utab.io
Receives searches when the built-in search URL remains in use.