Repository: electron/electron (language: cpp)

Issue:
Docs: Add `ipcRender.on()` security warning to security guide
### Preflight Checklist

- [x] I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/main/CONTRIBUTING.md) for this project.
- [x] I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/main/CODE_OF_CONDUCT.md) that this project adheres to.
- [x] I have searched the [issue tracker](https://www.github.com/electron/electron/issues) for a feature request that matches the one I want to file, without success.

### Problem Description

The security warning from [here](https://www.electronjs.org/docs/latest/tutorial/ipc#2-expose-ipcrendereron-via-preload) should be included in the [security guide](https://www.electronjs.org/docs/latest/tutorial/security).

It's currently hard to miss as issues like #45224 show.

### Proposed Solution

Include the warning in the security guide. This way anyone who reads the guide will double-check all their `ipcRenderer.on()` calls.

### Alternatives Considered

Leave everything as is. -> Leads to vulnerable code in the wild.

### Additional Information

_No response_


Discussion / hints:
Agreed, good idea.

Fix patch:
diff --git a/docs/tutorial/security.md b/docs/tutorial/security.md
index 66b4736da3778..12f2815788417 100644
--- a/docs/tutorial/security.md
+++ b/docs/tutorial/security.md
@@ -116,6 +116,7 @@ You should at least follow these steps to improve the security of your applicati
 17. [Validate the `sender` of all IPC messages](#17-validate-the-sender-of-all-ipc-messages)
 18. [Avoid usage of the `file://` protocol and prefer usage of custom protocols](#18-avoid-usage-of-the-file-protocol-and-prefer-usage-of-custom-protocols)
 19. [Check which fuses you can change](#19-check-which-fuses-you-can-change)
+20. [Do not expose Electron APIs to untrusted web content](#20-do-not-expose-electron-apis-to-untrusted-web-content)
 
 To automate the detection of misconfigurations and insecure patterns, it is
 possible to use
@@ -229,7 +230,7 @@ API to remotely loaded content via the [contextBridge API](../api/context-bridge
 ### 3. Enable Context Isolation
 
 :::info
-This recommendation is the default behavior in Electron since 12.0.0.
+Context Isolation is the default behavior in Electron since 12.0.0.
 :::
 
 Context isolation is an Electron feature that allows developers to run code
@@ -804,6 +805,48 @@ flipping these fuses easy. Check out the README of that module for more details
 potential error cases, and refer to
 [How do I flip the fuses?](./fuses.md#how-do-i-flip-the-fuses) in our documentation.
 
+### 20. Do not expose Electron APIs to untrusted web content
+
+You should not directly expose Electron's APIs, especially IPC, to untrusted web content in your
+preload scripts.
+
+### Why?
+
+Exposing raw APIs like `ipcRenderer.on` is dangerous because it gives renderer processes direct
+access to the entire IPC event system, allowing them to listen for any IPC events, not just the ones
+intended for them.
+
+To avoid that exposure, we also cannot pass callbacks directly through: The first
+argument to IPC event callbacks is an `IpcRendererEvent` object, which includes properties like `sender`
+that provide access to the underlying `ipcRenderer` instance. Even if you only listen for specific
+events, passing the callback directly means the renderer gets access to this event object.
+
+In short, we want the untrusted web content to only have access to necessary information and APIs.
+
+### How?
+
+```js title='preload'.js'
+// Bad
+contextBridge.exposeInMainWorld('electronAPI', {
+  on: ipcRenderer.on
+})
+
+// Also bad
+contextBridge.exposeInMainWorld('electronAPI', {
+  onUpdateCounter: (callback) => ipcRenderer.on('update-counter', callback)
+})
+
+// Good
+contextBridge.exposeInMainWorld('electronAPI', {
+  onUpdateCounter: (callback) => ipcRenderer.on('update-counter', (_event, value) => callback(value))
+})
+```
+
+:::info
+For more information on what `contextIsolation` is and how to use it to secure your app,
+please see the [Context Isolation](context-isolation.md) document.
+:::
+
 [breaking-changes]: ../breaking-changes.md
 [browser-window]: ../api/browser-window.md
 [webview-tag]: ../api/webview-tag.md


Test patch: