The `file://` protocol gets more privileges in Electron than in a browser, which allows attackers to load arbitrary files from users' machines. To prevent this, local pages should be served using custom protocols instead. 

== Why is this an issue?

In Electron, the `file://` protocol gets more privileges than other protocols do, such as `http` and `https`. Among other things, the `file://` protocol allows access to the entire local file system, which can be a security risk if not handled properly.

If an attacker is able to execute JavaScript within an Electron application that uses `file://` to serve local pages, then they can use this vulnerability to read any file on the user's machine. This works even if the renderer is fully isolated using sandboxing and context isolation.

By having access to the local file system, an attacker could read sensitive information stored on the user's machine, such as configuration files, credentials, or other sensitive data.

== How to fix it in Electron

=== Code examples

==== Noncompliant code example

[source,javascript,diff-id=1,diff-type=noncompliant]
----
const { app, BrowserWindow } = require('electron');

app.whenReady().then(() => {
    const win = new BrowserWindow({
        width: 800,
        height: 600,
    });

    win.loadFile(path.join(__dirname, 'index.html')); // Noncompliant
});
----

==== Compliant solution

This solution gives an example implementation of a custom protocol. It may need to be adapted to fit the specific needs of the application.

[source,javascript,diff-id=1,diff-type=compliant]
----
onst { app, net, protocol, BrowserWindow } = require('electron');

protocol.registerSchemesAsPrivileged([{
    scheme: 'app',
    privileges: {
        standard: true,
        secure: true,
        supportFetchAPI: true
    }
}]);

app.whenReady().then(() => {
    protocol.handle('app', (req) => {
        const url = new URL(req.url);
        if (url.hostname === 'local') {
            const requestedPath = url.pathname.substring(1);

            const pathToServe = path.resolve(__dirname, requestedPath);
            const relativePath = path.relative(__dirname, pathToServe);
            if (!relativePath && !relativePath.startsWith('..') && !path.isAbsolute(relativePath)) {
                return new Response('Only local application files are allowed', {status: 400});
            }

            return net.fetch(pathToFileURL(pathToServe).toString());
        } else {
            // Handle other types of requests
        }
    });

    const win = new BrowserWindow({
        width: 800,
        height: 600,
    });

    win.loadURL("app://local/index.html");
});
----

=== How does this work?

The compliant solution uses a custom protocol. By using this instead of the `file://` protocol, it becomes possible to limit the access to the local file system. In this case, the custom protocol is used to mimic local file requests. However, any request for a local file that is not part of the Electron application will be rejected.

== Resources
=== Documentation

* Electron - https://www.electronjs.org/docs/latest/tutorial/security#18-avoid-usage-of-the-file-protocol-and-prefer-usage-of-custom-protocols[Avoid usage of the file:// protocol and prefer usage of custom protocols]
* Electron - https://www.electronjs.org/docs/latest/api/protocol#protocolhandlescheme-handler[protocol.handle]


ifdef::env-github,rspecator-view[]

'''
== Implementation Specification
(visible only on this page)

=== Message
* Change this code to load using a custom protocol.

=== Highlighting

Highlight the entire `loadFile` or `loadURL` function call.

'''
== Comments And Links
(visible only on this page)

endif::env-github,rspecator-view[]

