Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bypassing CSP on Github? #881

Closed
SonOfDiablo opened this issue Feb 28, 2020 · 26 comments
Closed

Bypassing CSP on Github? #881

SonOfDiablo opened this issue Feb 28, 2020 · 26 comments
Milestone

Comments

@SonOfDiablo
Copy link

I'm trying to write a simple script that will replace elements on Github pages.

Expected Behavior

The element I target would be replaced and the JavaScript I'm trying to inject would be executed.

Actual Behavior

Getting a Refused to load the script...because it violates the following Content Security Policy directive error message in the console.

Full error message
Refused to load the script 'https://asciinema.org/a/14.js' because it violates the following Content Security Policy directive: "script-src 'unsafe-eval' github.githubassets.com". Note that 'script-src-elem' was not explicitly set, so 'script-src' is used as a fallback.

Specifications

  • Chromium: 79.0.3945.130
  • TM: 4.9
  • OS: Windows 10 Home Verson: 1909 Build: 18363

Script

// ==UserScript==
// @name         Asciinema Embedder
// @namespace    SOD-Scripts
// @version      0.1
// @description  Replaces image links to asciinema with an embedded player.
// @author       Son_Of_Diablo
// @match        https://github.com/*/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    const IMAGES = document.querySelectorAll('article.markdown-body img');

    for (const image of IMAGES) {
        if (!(image.hasAttribute('data-canonical-src'))) {
            continue;
        }

        const imageSrc = new URL(image.dataset.canonicalSrc);

        if (imageSrc.hostname !== 'asciinema.org') {
            continue;
        }

        const imageAnchorEl = image.parentNode;
        const castId = imageSrc.pathname.split('/a/')[1].split('.')[0];

        const playerScript = document.createElement('script');
        playerScript.setAttribute('src', "https://asciinema.org/a/14.js");
        playerScript.setAttribute('id', "asciicast-14");
        playerScript.setAttribute('async', true);

        imageAnchorEl.parentNode.replaceChild(playerScript, imageAnchorEl);
    }
})();

Tested in this repo: https://github.com/mingrammer/awesome-finder

@Owyn
Copy link

Owyn commented Mar 7, 2020

same on google images

btw, it doesn't happen without https everywhere in strict https only mode

not_running2
not_running1
ok1
ok2

Firefox: 73.0.1 (64bit)
TM: v4.10.6105
OS: Windows 10 Home Verson: 1903 Build: 18363

@SonOfDiablo
Copy link
Author

@Owyn I just tried installing HTTPS Everywhere and it didn't change anything.
Might be a difference between Chrome and Firefox? or the fact that you are using another version of TM than me. The Chrome version is still at 4.9

@Owyn
Copy link

Owyn commented Mar 7, 2020

Perhaps Firefox with HTTPS Everywhere behaves like Chrome without it cuz Chrome already has its functionality or something 🤔

@derjanb derjanb added this to the 4.10 milestone Mar 10, 2020
@derjanb
Copy link
Member

derjanb commented Mar 28, 2020

@SonOfDiablo TM BETA 4.10.6112 adds a new experimental API called GM_addScript, which can be used this way:

// @grant GM_addScript
[...]
let script_tag = GM_addScript('alert("works!");');

@Owyn
I'm linking the HTTPS Everywhere issue for reference: EFForg/https-everywhere#19008

@Owyn
Copy link

Owyn commented Mar 28, 2020

We could already do GM_addScript functionality before via adding <script> element into the page (same as with GM_AddStyle)

Plus won't that bring many troubles for the script including being unable to execute GM_ functions from the scope of the page?

but anyway... since scripts don't run at all due to CSP - neither will GM_addScript get the chance to ever run, no?

From testing - CSP issue isn't there after you just install TamperMonkey for the first time without restarting the browser and appears only after you restart the firefox, maybe investigating this could help fix it?

@SonOfDiablo
Copy link
Author

GM_addScript seems to just exactly as is described which is wonderful!
Thank you @derjanb for the heads up ^^

Though, I'm now running into the exact same CSP issue when trying to inject an iFrame.
Refused to frame 'https://asciinema.org/' because it violates the following Content Security Policy directive: "frame-src render.githubusercontent.com".

Is there already functionality for this in Tampermonkey or would that need to be added as well? (If you are interested in having that functionality of course)

@Owyn
Copy link

Owyn commented Apr 9, 2020

TM just got updated and I saw this fix in the changelist... and as I've thought there is just no chance to run GM_addScript or any other script code (even console.log) because of CSP
изображение

but right after TM new version got installed - it was working fine untill I restarted the browser

@SonOfDiablo
Copy link
Author

Works fine for me, even after browser restart.
@Owyn Is the github page you are testing on the first page that opens when you start your browser? Maybe there is some kind of race condition?

@Owyn
Copy link

Owyn commented Apr 9, 2020

@SonOfDiablo I'm on Firefox, you're on Chromium
Perhaps our situations are a bit different. But I've tested it on this page and all others including google images and navigating github for a while.

@derjanb
Copy link
Member

derjanb commented Apr 28, 2020

Though, I'm now running into the exact same CSP issue when trying to inject an iFrame.

Maybe GM_addElement would be a more generic solution. 🤔

@derjanb derjanb modified the milestones: 4.10, 4.11 Apr 28, 2020
@Owyn
Copy link

Owyn commented May 14, 2020

some more info: quickly disabling and enabling TM on Firefox's extension page makes it possible to run TM & scripts on github and other CSP sites (until browser restart as always), so no need to reinstall anything to reproduce this short-lived "fix"

@prenagha
Copy link

Would be great to get the Safari Mac App Store version updated with this feature. Thanks @derjanb

@derjanb
Copy link
Member

derjanb commented Jun 5, 2020

GM_addElement is part of TM BETA 4.11.6113.

Usage:

GM_addElement('script', { textContent: 'window.foo = "bar";' });

or

GM_addElement(shadowDOM, 'style', { textContent: 'div { color: black; };' });

@Owyn
Copy link

Owyn commented Jun 10, 2020

v6114 seems to have fixed CSP things quite a bit but... issue with https everywhere extension not allowing TM to run on CSP sites is still there

@strafe
Copy link

strafe commented Jul 20, 2020

@derjanb will this be a workaround to #296 as well?

@derjanb
Copy link
Member

derjanb commented Jul 20, 2020

@derjanb will this be a workaround to #296 as well?

Unfortunately, no.

@DerekZiemba
Copy link

DerekZiemba commented Feb 11, 2021

GM_addElement is part of TM BETA 4.11.6113.
Usage:

GM_addElement('script', { textContent: 'window.foo = "bar";' });

Where is GM_addElement documented? Nothing shows up on google for GM_addElement except this thread and the changelog. I have no idea what arguments it accepts, how it works, what parent it's appending the child element to, or when in the pages lifecycle the element is being appended.

I cloned the codebase to try to find it in code, but no branch has been updated in over 3 years!!. GM_addElement, GM_addScript, TM_addElement, and TM_addScript do not exist in the repo. environment.js hasn't been updated in 9 years and contains none of the recently added GM_xxx functions!

var GM_EMU = function() {
this.GM_addStyle = function(css) {
return TM_addStyle(css);
};

@derjanb How am I supposed to discover capabilities or know what API's are available and how to use them?

@derjanb
Copy link
Member

derjanb commented Feb 11, 2021

@DerekZiemba It was in fact only documented here: #881 (comment) 😉

I've added it to Tampermonkey's documenation.

GM_addElement(tag_name, attributes), GM_addElement(parent_node, tag_name, attributes)

Creates an HTML element specified by 'tag_name' and applies all given 'attributes' and returns the injected HTML element. If a 'parent_node' is given, then it is attached to it or to document head or body otherwise.

For suitable 'attributes', please consult the appropriate documentation. For example:

GM_addElement('script', {
  textContent: 'window.foo = "bar";'
});

GM_addElement('script', {
  src: 'https://example.com/script.js',
  type: 'text/javascript'
});

GM_addElement(document.getElementsByTagName('div')[0], 'img', {
  src: 'https://example.com/image.png'
});

GM_addElement(shadowDOM, 'style', {
  textContent: 'div { color: black; };'
});

@KaKi87
Copy link

KaKi87 commented Oct 26, 2021

Hello,

The addElement method successfully bypasses CSP on iframe, but only until the users clicks on an a element inside the iframe.

Thanks

@guansss
Copy link

guansss commented Feb 8, 2023

For JavaScript modules, usage of GM_addElement is still blocked by CSP. Is there any way to work around this?

// blocked by CSP
GM_addElement('script', {
  type: 'module',
  src: 'https://127.0.0.1:3000/my-script.js'
});

// not blocked, but throws syntax error since my-script.js is a module
GM_addElement('script', {
  src: 'https://127.0.0.1:3000/my-script.js'
});

// works
GM_addElement('script', {
  type: 'module',
  textContent: 'console.log("hello")'
});

// blocked again
GM_addElement('script', {
  type: 'module',
  textContent: 'import "https://127.0.0.1:3000/my-script.js"'
});

The reason I need modules is that I'm using Vite's dev server, in which I can benefit from the hot reload feature, but it only emits modules instead of vanilla JavaScript.

@derjanb
Copy link
Member

derjanb commented Jun 13, 2023

// blocked again

@guansss Please try @sandbox. #1186 (comment)

@guansss
Copy link

guansss commented Jun 14, 2023

@derjanb Thanks for the reply! However this does not seem to work, I've tried setting @sandbox to one of raw, JavaScript and DOM and the module script is always blocked.

The userscript I used for test:

// ==UserScript==
// @name         New Userscript
// @version      0.1
// @match        http://localhost:8080/*
// @grant        GM_addElement
// @sandbox      JavaScript
// ==/UserScript==

GM_addElement('script', {
  type: 'module',
  src: 'https://cdn.jsdelivr.net/npm/mitt@3.0.0/+esm'
});

The HTML source:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta
      http-equiv="Content-Security-Policy"
      content="default-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self';"
    />
  </head>
</html>

The error:

Refused to load the script 'https://cdn.jsdelivr.net/npm/mitt@3.0.0/+esm' because it violates the following Content Security Policy directive: "script-src 'self' 'unsafe-eval'". Note that 'script-src-elem' was not explicitly set, so 'script-src' is used as a fallback.

Chrome: 114.0.5735.134
Tampermonkey BETA: 4.19.6183

@7nik
Copy link

7nik commented Jun 14, 2023

You need to remove the CSP header/meta tag. See here https://github.com/lisonge/vite-plugin-monkey#csp the ways to do it

@guansss
Copy link

guansss commented Jun 15, 2023

@7nik Fully disabling CSP may be a security risk, and the risk also applies to everyone that is contributing to the userscript project and being required to do the same thing.

And speaking of plugins, I'm as well developing a webpack plugin that actually bypasses CSP without any configuration needed. It's still WIP, but you can check it out here: webpack-monkey.

@7nik
Copy link

7nik commented Jun 15, 2023

From TM's point of view, there is nothing wrong: the element (script) is created, inserted in the DOM and even executed. The error happens only at fetching the code.

Fully disabling CSP may be a security risk, and the risk also applies to everyone that is contributing to the userscript project and being required to do the same thing.

Dude, the whole Internet existed for two decades without CSP, and even more, most sites preferred HTTP until browsers started complaining about it.

If you want to keep the CSP, you can set up a local proxy to alter the CSP header/meta tag to whatever you want. You can probably even edit hosts to open the site under the original domain.

webpack-monkey.

No, thanks. I have a project that used webpack at begging, but when I replaced it with rollup, it started to run and compile 5-10 times faster with smaller output (less dead code). And, if I remember right, webpack doesn't allow top-level-await, which I wanted.

@freemedom
Copy link

freemedom commented Sep 13, 2023

@7nik Recently, Modify existing content security policy (CSP) headers in my browser does not work. Do you have this problem?
#1845

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

10 participants