Is Onelog safe?

High risk

Onelog is high risk. We observed Onelog posting to its localhost relay during browsing. Source shows navigation can build a BeforeNavigateRequest with the page URL, window/browser context, a resolved username; our test's agent stalled at the language probe.…

Info Technology Supply Ltdv2.10.2607.21Chrome Web Store
75Risk
Who publishes it

Info Technology Supply Limited - no other listings under this identity, 1 shared hostname

What this publisher told the store about itself, and the other listings that told it the same thing.

Publisher
Info Technology Supply Ltd
Declared legal entity
Info Technology Supply Limited
Registered address
2, Hobbs House, Bessborough Road, Harrow HA1 3EX, GB
Registered contact
James Wright

Shared hosts - 1 hostname

Hostnames hardcoded in this extension that few other listings call. That can mean one operator behind both, and it can equally mean a small shared vendor, so it is context rather than a conclusion. Hosts that many listings call are left out: they are services, not connections.

thedailybeast.com
Also called by 4 other listings, including Unlock (Paywalls)

AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.

Publishers can request a review.

Findings

SeverityHIGH
ClassUNWANTED
TypeUnexpected
CWECWE-359
SourceAI SANDBOX

Navigation URLs Posted to Onelog Localhost Relay

We observed Onelog posting to its localhost relay during browsing.

Source shows navigation can build a BeforeNavigateRequest with the page URL, window/browser context, a resolved username; our test's agent stalled at the language probe.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You open or navigate to a web page.

The extension did this

Onelog prepares a navigation record and sends JSON to its local relay service.

02EvidenceNETWORK CAPTURE
Captured request
POSThttp://localhost:12345/index/
Repeated localhost relay POSTs were observed; the URL-bearing BeforeNavigateRequest body was not captured because the desktop-agent handshake did not complete.
Headers
Content-Typeapplication/json
Body
{
  "LanguageItems": {}
}
03EvidenceFIELD TABLE
Fields assembled for BeforeNavigateRequest
FieldValueWhy it matters
Page URL
https://example.com/Shows the exact page you were opening, including path and query text when present.
Resolved username
jane.doe@example.com (illustrative)Can connect the browsing event to a specific signed-in person when Onelog has resolved a username.
Window and tab context
WindowId 2, WindowHandle 1 (illustrative)Adds browser context that ties the page visit to a specific tab and window.
Browser type
chromeIdentifies the browser family used for the page visit.
04EvidenceCODE COMPARE
The code that does this

Navigation event and request construction

What it actually does
Navigation listener calls the request senderdeobfuscated/extensionEvents.js
olExtension.Listeners._internal.Events = {
    _beforeNavigateEvent: function (event) {
        try {
            var alertContent_ = new olFunctions.AlertContent('EVT Before navigate event', 'Caught by extension Url: ' + event.target.getUrl());
            if (event.target.url == olExtension.Data.LogoutUrl) {
                olExtension._internal.HandleLogoutWindow(event);
            } else {
                //Check logout array
                if (olData.LogoutTabs.indexOf(event.target.getId()) == -1) {
                    // not a logout tab
                    var tabId_ = event.target.getId();

                    chrome.webNavigation.getAllFrames({ tabId: tabId_ }, function (result) {
                        try {

                            var framesArray_ = [];
                            for (var i = 0; i < result.length; i++) {
                                var currentFrame_ = result[i];
                                var currentFrameId_ = currentFrame_.frameId;

                                framesArray_.push(currentFrameId_)
                            }
                        } catch (e) {
                            framesArray_ = [];

                            var alertErrorContent_ = new olFunctions.AlertContent('_beforeNavigateEvent chrome.webNavigation.getAllFrames', e.message + ' ' + e.stack);
                            olFunctions.Alert(olOptions.Errors(), alertErrorContent_, 'error');
                        } finally {
                            var tabMember_ = olExtension._internal.TabMember.Create(event.target.getId(), event.target.getUrl(), framesArray_);
                            var urlDomain_ = olFunctions.GetDomainFromUrl(event.target.getUrl());

                            if (urlDomain_ && (ol$Functions.inArray(urlDomain_, tabMember_.Domains) == -1)) {
                                tabMember_.Domains.push(urlDomain_);
                            }

                            var requestContent_ = new olExtension.DataConstructors.RequestContent(tabMember_);
                            olExtension.Service.BeforeNavigateRequestSend(requestContent_);
                        }
                    })
                } else {
                    // logout tab
                    return;
                }
            }
            olFunctions.Alert(olOptions.DebugApiMess(), alertContent_, 'apimessevent');
        } catch (e) {
            var alertErrorContent_ = new olFunctions.AlertContent('_beforeNavigateEvent', e.message + ' ' + e.stack);
            olFunctions.Alert(olOptions.Errors(), alertErrorContent_, 'error');
        }
    },
    BeforeNavigate: function () {
        olWrap.browser.addEventListener(olWrap.browser.event.BeforeNavigate, function (event) {
            try {
                var waitingForSw_Init = setInterval(function () {
                    if (olExtension.Data.SW_Initialised) {
                        clearInterval(waitingForSw_Init);
                        if (event.url != null && !olWrap.urlExcluded(event.url)) {
                            olExtension.Listeners._internal.Events._beforeNavigateEvent(event);
                        }
                    }
                }, 50)
            } catch (e) {
                var alertErrorContent_ = new olFunctions.AlertContent('BeforeNavigate', e.message + '\n' + e.stack);
                olFunctions.Alert(olOptions.Errors(), alertErrorContent_, 'error');
            }
        });
    },
BeforeNavigateRequest fieldsdeobfuscated/extensionApiService.js
BeforeNavigateRequestSend: function (requestContent, processRequestSuccess) {
        try {
            requestContent.TabMember._internal.ExtensionFlags.BeforeNavigateRequestSent = true;
            var alertContent_ = new olFunctions.AlertContent('API Before navigate request sent', 'Url: ' + requestContent.TabMember._internal.GetUrl());
            var successFunction_ = olExtension.Service._internal.SetSuccessFunction(processRequestSuccess, olExtension.Service._internal.SuccessBeforeNavigateRequest);
            var browserName_ = olData.BrowserName;
            var ajaxData_ = {
                BeforeNavigateRequest: {
                    URL: requestContent.TabMember.PageInfo.RequestUrl,
                    // URL: requestContent.TabMember._internal.GetUrl(),
                    WindowId: requestContent.TabMember.WindowId,
                    SessionSetId: 1,
                    WindowHandle: requestContent.TabMember.WindowHandle,
                    BrowserType: (browserName_ == olWrap.browser.name.edg ? 'chrome' : browserName_),
                    NewEdgeCompatibility: (browserName_ == olWrap.browser.name.edg)
                }
            };

            if (olExtension._internal.UsernameResolved) {
                ajaxData_.BeforeNavigateRequest.Username = olExtension._internal.Username
            }

            var sendRequestParams_ = new olExtension.DataConstructors.SendRequestParameters('BeforeNavigateRequest', ajaxData_, requestContent, successFunction_);
            olExtension.Service._internal.SendRequest(sendRequestParams_);

            olFunctions.Alert(olOptions.DebugApiMess(), alertContent_, 'apimessevent');
        } catch (e) {
            var alertErrorContent_ = new olFunctions.AlertContent('BeforeNavigateRequestSend', e.message + '\n' + e.stack);
            olFunctions.Alert(olOptions.Errors(), alertErrorContent_, 'error');
        }
    },
Shared JSON POST transportdeobfuscated/extensionApiService.js
_SendRequestFetch: async function (sendRequestParameters) {
            const response = await fetch(olOptions.General.Extension.ServerUrl(), {
                method: sendRequestParameters.AjaxParam.Type,
                cache: 'no-cache',
                timeout: sendRequestParameters.AjaxParam.Timeout,
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify(sendRequestParameters.AjaxParam.Data) // body data type must match "Content-Type" header
            });
            return response.json();
        },
Localhost relay settingdeobfuscated/modOptions.js
{
            Name: 'ServerUrl',
            Visible: false,
            Label: 'Server URL',
            Value: 'http://localhost:12345/index/',
            DefaultValue: 'http://localhost:12345/index/',
            ElementOptions: null,
            ObjectId: 'olServerURL',
            Type: 'internal',
            ParentId: 'olAdministratorSettings'
        },
05EvidenceTHIRD PARTY LIST
Destination used by this flow
  • localhost

    Onelog local relay service on port 12345 receives JSON request types including LanguageItems and, when the handshake permits, BeforeNavigateRequest.

SeverityHIGH
ClassUNWANTED
TypeUnexpected
CWECWE-359
SourceAI SANDBOX

Page Titles Sent After Onelog Navigation Completion

Onelog source records the document title for a tab and builds a DocumentCompleteRequest with that title and session ID.

We observed posts to the same relay during testing, but this request needs a successful desktop-agent chain, uncaptured.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You load a page whose title is visible to the extension.

The extension did this

Onelog stores the title and can include it in a completion request to its local relay.

02EvidenceNETWORK CAPTURE
Captured request
POSThttp://localhost:12345/index/
Localhost relay POSTs were observed after page load; the DocumentCompleteRequest body was not captured without a valid navigate-complete response.
Headers
Content-Typeapplication/json
Body
{
  "LanguageItems": {}
}
03EvidenceFIELD TABLE
Fields assembled for DocumentCompleteRequest
FieldValueWhy it matters
Page title
Example DomainCan reveal which page or account view you opened even when the URL is not shown.
Application session ID
ApplicationSessionId 42 (illustrative)Links the completed page load to the application session tracked by Onelog.
Response flags
Ignore=false, TurnAway=false (illustrative)Carries control flags from the earlier navigation response into the completion record.
04EvidenceCODE COMPARE
The code that does this

Document title capture and completion request

What it actually does
The page title is stored on the tab recorddeobfuscated/extensionMessaging.js
if (!tabMember_._internal.ExtensionFlags.BeforeNavigateRequestSent) {
                                            var requestContent_ = new olExtension.DataConstructors.RequestContent(tabMember_);
                                            olExtension.Service.BeforeNavigateRequestSend(requestContent_);
                                        }

                                        tabMember_._internal.ExtensionFlags.DocumentReady = true;
                                        tabMember_.DocumentTitle = documentTitle;

                                        var messageContent_ = new olExtension.DataConstructors.MessageContent(tabMember_);
Navigate-complete success invokes DocumentCompleteRequestSenddeobfuscated/extensionApiService.js
SuccessNavigateCompleteRequest: function (requestResult, requestContent) {
            try {
                var alertContent_ = new olFunctions.AlertContent('API Success Navigate complete request succeeded', 'Url: ' + requestContent.TabMember.PageInfo.Url);
                if (olFunctions.IsFilledArray(requestResult.NavigateCompleteResponses)) {
                    if (requestResult.NavigateCompleteResponses.length > 1) {
                        var navigateResponse_ = requestResult.NavigateCompleteResponses[1];

                        var filterMembers_ = olExtension._internal.TabMember.Filter(null, null, null, navigateResponse_.ApplicationsSessionId);
                        if (navigateResponse_.ApplicationsSessionId && olFunctions.IsFilledArray(filterMembers_)) {
                            var tabMember_ = filterMembers_[0];
                            tabMember_.PageInfo.ClosingResponse = navigateResponse_;
                            olExtension._internal.TabMember.HandleResourceEnd(tabMember_);
                        }
                    }

                    var ncr0_ = requestResult.NavigateCompleteResponses[0];
                    //and send pause duration
                    if (!(ncr0_.PauseDuration && ncr0_.PauseDuration > 0)) {
                        ncr0_.PauseDuration = 0;
                    }
                    requestContent.TabMember.PageInfo.Response.BeforeNavigateResponses[0].PauseDuration = ncr0_.PauseDuration;
                    // send pause duration back to tab
                    var pauseDuration_ = {
                        ApplicationName: ncr0_.ApplicationName,
                        PauseDuration: ncr0_.PauseDuration
                    };
                    var messageContent_ = new olExtension.DataConstructors.MessageContent(requestContent.TabMember, pauseDuration_);
                    olExtension.Messages.PauseDuration(messageContent_);
                }

                olExtension.Service.DocumentCompleteRequestSend(requestContent);
                olFunctions.Alert(olOptions.DebugApiMess(), alertContent_, 'apimessevent');
            } catch (e) {
                var alertErrorContent_ = new olFunctions.AlertContent('SuccessNavigateCompleteRequest', e.message + '\n' + e.stack);
                olFunctions.Alert(olOptions.Errors(), alertErrorContent_, 'error');
            }
        },
DocumentCompleteRequest fieldsdeobfuscated/extensionApiService.js
DocumentCompleteRequestSend: function (requestContent, processRequestSuccess) {
        try {
            if (!requestContent.TabMember._internal.ExtensionFlags.DocumentCompleteRequestSent) {
                requestContent.TabMember._internal.ExtensionFlags.DocumentCompleteRequestSent = true;

                var alertContent_ = new olFunctions.AlertContent('API Document complete request sent', 'Url: ' + requestContent.TabMember.PageInfo.Url);
                var successFunction_ = olExtension.Service._internal.SetSuccessFunction(processRequestSuccess, olExtension.Service._internal.SuccessDocumentCompleteRequest);
                var ajaxData_ = {
                    DocumentCompleteRequest: {
                        WindowTitle: requestContent.TabMember.DocumentTitle,
                        ApplicationSessionId: requestContent.TabMember.ApplicationsSessionId,
                        Ignore: requestContent.TabMember.PageInfo.Response.BeforeNavigateResponses[0].Ignore,
                        TurnAway: requestContent.TabMember.PageInfo.Response.BeforeNavigateResponses[0].TurnAway,
                        TurnAwaySpecified: requestContent.TabMember.PageInfo.Response.BeforeNavigateResponses[0].TurnAwaySpecified
                    }
                };
                var sendRequestParams_ = new olExtension.DataConstructors.SendRequestParameters('DocumentCompleteRequest', ajaxData_, requestContent, successFunction_);
                olExtension.Service._internal.SendRequest(sendRequestParams_);

                olFunctions.Alert(olOptions.DebugApiMess(), alertContent_, 'apimessevent');
            }
        } catch (e) {
            var alertErrorContent_ = new olFunctions.AlertContent('DocumentCompleteRequestSend', e.message + '\n' + e.stack);
            olFunctions.Alert(olOptions.Errors(), alertErrorContent_, 'error');
        }
    },
Shared JSON POST transportdeobfuscated/extensionApiService.js
_SendRequestFetch: async function (sendRequestParameters) {
            const response = await fetch(olOptions.General.Extension.ServerUrl(), {
                method: sendRequestParameters.AjaxParam.Type,
                cache: 'no-cache',
                timeout: sendRequestParameters.AjaxParam.Timeout,
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify(sendRequestParameters.AjaxParam.Data) // body data type must match "Content-Type" header
            });
            return response.json();
        },
05EvidenceTHIRD PARTY LIST
Destination used by this flow
  • localhost

    Onelog local relay service on port 12345 receives JSON request types including LanguageItems and, when the response chain permits, DocumentCompleteRequest.

SeverityHIGH
ClassUNWANTED
TypeUnexpected
CWECWE-522
SourceAI SANDBOX

Shared Password Flow Relays Credentials via Localhost

Onelog's shared-password overlay can send a selected user name and password-details user ID to its localhost relay, then process a SharedPasswordsResponse and dispatch data to page content.

Confirmed from code, not a captured request.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You select a shared-password user inside the Onelog page overlay.

The extension did this

Onelog requests shared password data from the local relay and sends the response back to the page.

02EvidenceNETWORK CAPTURE
Captured request
POSThttp://localhost:12345/index/
The GetSharedPasswordsRequest is posted to this URL by the shared fetch transport; no password-request body was captured in traffic because the overlay and desktop-agent conditions were not present.
Headers
Content-Typeapplication/json
03EvidenceFIELD TABLE
Fields and credential data in the shared-password flow
FieldValueWhy it matters
Selected user name
shared.user@example.com (illustrative)Identifies the shared-password account entry selected in the overlay.
Password details user ID
PasswordDetailsUserId 18472 (illustrative)Links the request to the stored shared-password record for that selected user.
Application session ID
ApplicationSessionId 42 (illustrative)Associates the shared-password request with the application session Onelog is tracking.
Returned shared password data
SharedPasswordsResponse.SharedPasswordsUser.VariableReplacement.PersonalDetail (source field)Password replacement data can be sent back into page content for form filling.
04EvidenceCODE COMPARE
The code that does this

Shared-password request and response dispatch

What it actually does
Overlay click collects selected shared user detailsdeobfuscated/page.js
SelectedSharedUser_onClick: function (event) {
                            try {
                                olInjection.Parameters.ForcedInjected = false;

                                var parameters_ = {
                                    UserName: event.data.UserName,
                                    UserId: event.data.UserId,
                                    Title: event.data.Title,
                                };
                                olPage.Content.Divs.Close.PromptChooseSharedUserToUsePasswordsFrom(false);
                                olPage.Messages.GetSharedPasswordsRequest(parameters_);
                            } catch (e) {
                                var alertErrorContent_ = new olFunctions.AlertContent('SelectedSharedUser_onClick', e.message + '\n' + e.stack);
                                olFunctions.Alert(olOptions.Errors(), alertErrorContent_, 'error');
                            }
                        },
Extension receives the page messagedeobfuscated/extensionMessaging.js
GetSharedPasswordsRequest: function () {
                olWrap.addMessageListener('olGetSharedPasswordsRequest', function (event) {
                    try {
                        var alertContent_ = new olFunctions.AlertContent('MSG Get shared password message', 'Received by extension Url: ' + event.target.getUrl());

                        var waitingForSw_Init = setInterval(function () {
                            if (olExtension.Data.SW_Initialised) {
                                clearInterval(waitingForSw_Init);

                                var tabUrl_ = event.url;
                                var tabId_ = event.target.getId();
                                var filterTabMembers_ = olExtension._internal.TabMember.Filter(olExtension.Data.WindowHandle, tabId_, tabUrl_, null);
                                var tabMember_ = filterTabMembers_[0];

                                var requestContent_ = new olExtension.DataConstructors.RequestContent(tabMember_, event.data);
                                olExtension.Service.GetSharedPasswordsRequestSend(requestContent_);
                                olFunctions.Alert(olOptions.DebugApiMess(), alertContent_, 'apimessevent');
                            }
                        }, 50)
                    } catch (e) {
                        var alertErrorContent_ = new olFunctions.AlertContent('GetSharedPasswordsRequest', e.message + '\n' + e.stack);
                        olFunctions.Alert(olOptions.Errors(), alertErrorContent_, 'error');
                    }
                });
            },
GetSharedPasswordsRequest fieldsdeobfuscated/extensionApiService.js
GetSharedPasswordsRequestSend: function (requestContent, processRequestSuccess) {
        try {
            var alertContent_ = new olFunctions.AlertContent('API Get shared passwords request sent', 'Url: ' + requestContent.TabMember.PageInfo.Url);
            var successFunction_ = olExtension.Service._internal.SetSuccessFunction(processRequestSuccess, olExtension.Service._internal.SuccessGetSharedPasswordsRequest);
            var ajaxData_ = {
                GetSharedPasswordsRequest: {
                    ApplicationSessionId: requestContent.TabMember.ApplicationsSessionId,
                    UserName: requestContent.Parameters.UserName,
                    PasswordDetailsUserId: requestContent.Parameters.UserId
                }
            };

            var sendRequestParams_ = new olExtension.DataConstructors.SendRequestParameters('GetSharedPasswordsRequest', ajaxData_, requestContent, successFunction_);
            olExtension.Service._internal.SendRequest(sendRequestParams_);
            olFunctions.Alert(olOptions.DebugApiMess(), alertContent_, 'apimessevent');
        } catch (e) {
            var alertErrorContent_ = new olFunctions.AlertContent('GetSharedPasswordsRequestSend', e.message + '\n' + e.stack);
            olFunctions.Alert(olOptions.Errors(), alertErrorContent_, 'error');
        }
    },
Returned shared-password data is processeddeobfuscated/extensionApiService.js
SuccessGetSharedPasswordsRequest: function (requestResult, requestContent) {
            try {
                var alertContent_ = new olFunctions.AlertContent('API Success Get shared users passwords succeeded', 'Url: ' + requestContent.TabMember.PageInfo.Url);

                if (requestResult.SharedPasswordsResponse && olFunctions.IsFilledArray(requestResult.SharedPasswordsResponse.SharedPasswordsUser.VariableReplacement.PersonalDetail)) {
                    if (!requestResult.SharedPasswordsResponse.SharedPasswordsUser.VariableReplacement) {
                        requestResult.SharedPasswordsResponse.SharedPasswordsUser.VariableReplacement = {};
                    }
                    if (!requestResult.SharedPasswordsResponse.SharedPasswordsUser.VariableReplacement.Variables) {
                        requestResult.SharedPasswordsResponse.SharedPasswordsUser.VariableReplacement.Variables = [];
                    }

                    var usernameArray_ = requestContent.TabMember.PageInfo.DefinedNames.UsernameArray;
                    var passwordArray_ = requestContent.TabMember.PageInfo.DefinedNames.PasswordArray;
                    var matterArray_ = requestContent.TabMember.PageInfo.DefinedNames.MatterArray;
                    var timeKeeperArray_ = requestContent.TabMember.PageInfo.DefinedNames.TimeKeeperArray;
                    var commentArray_ = requestContent.TabMember.PageInfo.DefinedNames.CommentArray;
                    var shareVariableRepacement_ = requestResult.SharedPasswordsResponse.SharedPasswordsUser.VariableReplacement;
                    olExtension.Service._internal._populateVariableReplacements(usernameArray_, shareVariableRepacement_);
                    olExtension.Service._internal._populateVariableReplacements(passwordArray_, shareVariableRepacement_);
                    olExtension.Service._internal._populateVariableReplacements(matterArray_, shareVariableRepacement_);
                    olExtension.Service._internal._populateVariableReplacements(timeKeeperArray_, shareVariableRepacement_);
                    olExtension.Service._internal._populateVariableReplacements(commentArray_, shareVariableRepacement_);


                    requestContent.TabMember.PageInfo.Response.SharedPasswordsResponse = requestResult.SharedPasswordsResponse;
                } else {
                    requestContent.TabMember.PageInfo.Response.SharedPasswordsResponse = {
                        SharedPasswordsUser: {
                            VariableReplacement: {
                                PersonalDetail: []
                            }
                        }
                    };
                }
                var messageContent_ = new olExtension.DataConstructors.MessageContent(requestContent.TabMember, requestResult.SharedPasswordsResponse);
                messageContent_.TabMessageContent.Parameters = requestContent.Parameters;
                olExtension.Messages.GetSharedPasswordsDispatchResponse(messageContent_);

                olFunctions.Alert(olOptions.DebugApiMess(), alertContent_, 'apimessevent');
            } catch (e) {
                var alertErrorContent_ = new olFunctions.AlertContent('SuccessRequestGetSharedUsersRequest', e.message + '\n' + e.stack);
                olFunctions.Alert(olOptions.Errors(), alertErrorContent_, 'error');
            }
        },
Response is dispatched back to page contentdeobfuscated/extensionMessaging.js
GetSharedPasswordsDispatchResponse: function (messageContent) {
        try {
            var alertContent_ = new olFunctions.AlertContent('MSG Get shared passwords request response message', 'Sent by extension');
            olExtension.Messages._internal.DispatchMessageToTab('olResponseToGetSharedPasswordsRequest', messageContent);

            olFunctions.Alert(olOptions.DebugApiMess(), alertContent_, 'apimessevent');
        } catch (e) {
            var alertErrorContent_ = new olFunctions.AlertContent('GetSharedPasswordsDispatchResponse', e.message + '\n' + e.stack);
            olFunctions.Alert(olOptions.Errors(), alertErrorContent_, 'error');
        }
    },
05EvidenceTHIRD PARTY LIST
Destination used by this flow
  • localhost

    Onelog local relay service on port 12345 receives the shared-password request and returns SharedPasswordsResponse data to the extension.

+1 more finding not shown

What it can do

Permissions this extension asks for, as declared in version 2.10.2511.5. Asking for a permission is not a finding on its own - it is what the extension can do if it chooses to. The current listed version is 2.10.2607.21, which we have not unpacked yet.

  • Read and change your data on every site you visit

    http://*/*

  • Read and change your data on every secure site you visit

    https://*/*

  • See the address and title of every tab you have open

    tabs

  • Run its own code inside the pages you visit

    scripting

  • See every page you navigate to, as you navigate to it

    webNavigation

  • Read and change cookies, including the ones that keep you signed in

    cookies

  • Keep running in the background while your browser is open

    background

  • Store data in your browser

    storage

  • Store an unlimited amount of data in your browser

    unlimitedStorage

  • Read information about your displays

    system.display

Updated 30 September 2026onjjmhhddjeopkhboiehpmhihjmoecpi