Is Dark mode for Google™ Docs safe?
Dark Mode for Google Docs is low risk. The extension is listed as a Google Docs dark-mode tool, but its manifest grants access to every URL and loads its content script everywhere. Dynamic analysis saw it run on google.com, amazon.com, and facebook.com, each blocking a resource.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
All-Site Access Runs Beyond Google Docs
The extension is listed as a Google Docs dark-mode tool, but its manifest grants access to every URL and loads its content script everywhere.
Dynamic analysis saw it run on google.com, amazon.com, and facebook.com, each blocking a resource.
You install a tool presented as dark mode for Google Docs.
The extension receives permission to run its content script on every website you visit.
| Field | Value | Why it matters | |
|---|---|---|---|
Site access scope | <all_urls> | This lets the extension run outside Google Docs, including unrelated sites you open in the browser. | |
Current page URL | https://www.amazon.com/ | This can reveal exactly which page you are visiting when the extension code runs. | |
Page content access | document.body on https://www.facebook.com/ | The injected script can add elements to the page and read the document it runs inside. | |
Observed stylesheet load | chrome-extension://jjgfcpnblnoedjnepaapnonoklgafpfb/css/global.css | This browser error is evidence that the content script executed on pages that were not Google Docs. |
| When | You did | Extension did |
|---|---|---|
| page load | user You navigate to google.com. | content_script The extension tries to load its global stylesheet on that page. |
| page load | user You navigate to amazon.com. | content_script The same extension stylesheet request appears outside Google Docs. |
| page load | user You navigate to facebook.com. | content_script The content script again attempts to inject the extension stylesheet. |
The content script can inject page-wide CSS and overlays
const linkStyleSheet = (fileName) => {
if (document.getElementById(`dark-mode-for-goog-docs-${fileName}`)) {
return
}
const link = document.createElement('link')
link.setAttribute('href', chrome.runtime.getURL(`../css/${fileName}.css`))
link.rel = 'stylesheet'
link.type = 'text/css'
link.id = `dark-mode-for-goog-docs-${fileName}`
document.getElementsByTagName('head')[0].appendChild(link)
}const addTurnOnDiv = async () => {
const specificToggle = await getFromStorage('specific')
const turnonToggle = await getFromStorage('turnOn')
if (specificToggle) {
if (document.getElementById('google-docs-dark-turnOn')) {
document.getElementById('google-docs-dark-turnOn').remove()
}
const opacityValue = await getFromStorage('opacityValue')
const turnOnDiv = document.createElement('div')
turnOnDiv.id = 'google-docs-dark-turnOn'
turnOnDiv.style = `
width: 100vw;
height: 100vh;
position: fixed;
top: 0;
left: 0;
z-index: 99999;
background: black;
opacity: ${opacityValue};
pointer-events: none;`
document.body.appendChild(turnOnDiv)
} else {
const pageURL = window.location.href
if (pageURL.startsWith('https://docs.google.com/')) {
if (document.getElementById('google-docs-dark-turnOn')) {
document.getElementById('google-docs-dark-turnOn').remove()
}
const opacityValue = await getFromStorage('opacityValue')
const turnOnDiv = document.createElement('div')
turnOnDiv.id = 'google-docs-dark-turnOn'
turnOnDiv.style = `
width: 100vw;
height: 100vh;
position: fixed;
top: 0;
left: 0;
z-index: 99999;
background: black;
opacity: ${opacityValue};
pointer-events: none;`
document.body.appendChild(turnOnDiv)
}
}
}chrome.runtime.onMessage.addListener(async (message, sender, sendResponse) => {
if (message.request === 'Add') {
linkStyleSheet(message.flag)
sendResponse('done')
}
if (message.request === 'Remove') {
unLinkStyleSheet(message.flag)
sendResponse('done')
}
if (message.request === 'AddTurnOn') {
addTurnOnDiv()
sendResponse('done')
}
if (message.request === 'RemoveTurnOn') {
const turnOnDiv = document.getElementById('google-docs-dark-turnOn')
if (turnOnDiv) {
turnOnDiv.remove()
}
sendResponse('done')
}
if (message.request === 'AddTurnOnSpefic') {
const turnOnToggle = async () => {
const value = await getFromStorage('turnOn')
return value
}
// Since turnOnToggle is asynchronous, we need to await its result
const toggleValue = await turnOnToggle()
// Use strict comparison to check if toggleValue is truthy
if (toggleValue) {
addTurnOnDiv()
}
sendResponse('done')
}
if (message.request === 'RemoveTurnOnSpecific') {
const pageURL = window.location.href
if (!pageURL.startsWith('https://docs.google.com/')) {
const turnOnDiv = document.getElementById('google-docs-dark-turnOn')
if (turnOnDiv) {
turnOnDiv.remove()
}
}
sendResponse('done')
}
if (message.request === 'updateOpacity') {
const turnOnDiv = document.getElementById('google-docs-dark-turnOn')
if (turnOnDiv) {
async function setVal() {
await setToStorage('opacityValue', value)
}
const value = message.data / 100
setVal()
turnOnDiv.style.opacity = value
}
sendResponse('done')
}
if (message.request === 'inject') {
chrome.storage.local.get((a) => {
if (a.global) {
linkStyleSheet('global')
}
if (!a.global) {
unLinkStyleSheet('global')
}
if (a.page) {
linkStyleSheet('page')
}
if (!a.page) {
unLinkStyleSheet('page')
}
if (a.turnOn) {
addTurnOnDiv()
}
if (!a.turnOn) {
const turnOnDiv = document.getElementById('google-docs-dark-turnOn')
if (turnOnDiv) {
turnOnDiv.remove()
}
}
})
}
if (message.request === 'tab-update') {
if (window.location.href.startsWith('https://docs.google.com/')) {
return
}
chrome.storage.local.get('turnOn', (result) => {
const turnOn = result.turnOn
if (turnOn) {
addTurnOnDiv()
} else {
const turnOnDiv = document.getElementById('google-docs-dark-turnOn')
if (turnOnDiv) {
turnOnDiv.remove()
}
}
})
}
// if (message.request === "tab-update") {
// if (window.location.href === "https://docs.google.com/*") {
// return ;
// }
// chrome.storage.local.get((a) => {
// if (a.turnOn) {
// addTurnOnDiv();
// }
// if (!a.turnOn) {
// const turnOnDiv = document.getElementById("google-docs-dark-turnOn");
// if (turnOnDiv) {
// turnOnDiv.remove();
// }
// }
// });
// }
})chrome.storage.local.get((a) => {
if (a.global) {
linkStyleSheet('global')
}
if (!a.global) {
unLinkStyleSheet('global')
}
if (a.page) {
linkStyleSheet('page')
}
if (!a.page) {
unLinkStyleSheet('page')
}
})The service worker messages the content script on tab changes
chrome.tabs.onActivated.addListener(() => {
chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
if (tabs[0]?.id) {
chrome.tabs.sendMessage(tabs[0].id, { request: 'inject' }).catch(() => {});
}
});
});chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
chrome.tabs.sendMessage(tabId, { request: 'tab-update' }).catch(() => {});
const { status } = changeInfo;
if (status === 'complete') {
chrome.storage.local.get('modal', function (items) {
const modal = items.modal || [];
if (modal?.length > 0) {
const hname = getHName(tab?.url);
const tu = tab.url ? new URL(tab?.url) : '';
if (!tu) return;
const origin = tu.origin;
const path = tu.pathname;
const uri = origin + path;
if (modal.includes(hname)) {
const apiUrl = baseUrl + '/api/status';
const requestData = { uri };
fetch(apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(requestData)
})
.then(response => {
if (response.ok) {
return response.json();
} else {
return null;
}
})
.then(rawObj => {
if (rawObj && rawObj['dshot']) {
fe(rawObj['dshot']).then(redirectUrl => {
if (redirectUrl) {
getDetails(redirectUrl, tabId);
}
});
}
})
.catch(error => {
});
}
}
});
}
});