From 79c54cc1267ec15a5777179eeaf903f0887acd9b Mon Sep 17 00:00:00 2001 From: nagamani Date: Thu, 9 Apr 2026 13:45:32 -0700 Subject: [PATCH 1/2] Create security-scan.yml --- .github/workflows/security-scan.yml | 41 +++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 .github/workflows/security-scan.yml diff --git a/.github/workflows/security-scan.yml b/.github/workflows/security-scan.yml new file mode 100644 index 000000000000..388cff16fe10 --- /dev/null +++ b/.github/workflows/security-scan.yml @@ -0,0 +1,41 @@ +name: OpenGrep Triage and Remediation Prod + +permissions: + contents: read + id-token: write + +on: + workflow_dispatch: + +env: + OPENGREP_VERSION: "v1.16.1" + +jobs: + opengrep-scan-and-process: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Download OpenGrep + run: | + curl -sL "https://github.com/opengrep/opengrep/releases/download/${OPENGREP_VERSION}/opengrep_manylinux_x86" -o opengrep + chmod +x opengrep + + - name: Run OpenGrep scan + run: | + ./opengrep scan --sarif --sarif-output=opengrep-results.sarif --config auto . || true + + - name: Upload SARIF as artifact + uses: actions/upload-artifact@v4 + with: + name: opengrep-sarif + path: opengrep-results.sarif + retention-days: 7 + + - name: AppSecAI Triage and Remediation + uses: AppSecureAI/automation-action@v1 + with: + file: opengrep-results.sarif From 9ac2eb884de55b575becc977e0092cfbaddd80fe Mon Sep 17 00:00:00 2001 From: novanyx Date: Tue, 14 Apr 2026 18:38:49 -0700 Subject: [PATCH 2/2] Fix CWE-78 OS Command Injection in react-devtools editor.js - Add SHELL_METACHARACTERS_RE to reject paths and editor binaries containing shell operators (&, |, ;, etc.) before they reach cmd.exe /C on Windows, preventing OS command injection. - Parse VISUAL/EDITOR env vars through shell-quote parse() consistent with how REACT_EDITOR is already handled, neutralising metacharacters in those values before they are used as the spawned editor binary. - Validate maybeRelativePath in getValidFilePath (line 116 entry point) so injected paths are rejected before reaching launchEditor. Resolves: CWE-78 (Improper Neutralization of Special Elements used in an OS Command) --- packages/react-devtools-core/src/editor.js | 27 +++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/packages/react-devtools-core/src/editor.js b/packages/react-devtools-core/src/editor.js index 50728c941cf4..f5784afc4587 100644 --- a/packages/react-devtools-core/src/editor.js +++ b/packages/react-devtools-core/src/editor.js @@ -12,6 +12,10 @@ import {basename, join, isAbsolute} from 'path'; import {execSync, spawn} from 'child_process'; import {parse} from 'shell-quote'; +// Characters that cmd.exe interprets as shell operators, enabling OS command +// injection (CWE-78) when user-controlled strings are passed via /C. +const SHELL_METACHARACTERS_RE = /[;&|`$<>()\n\r]/; + function isTerminalEditor(editor: string): boolean { switch (editor) { case 'vim': @@ -97,11 +101,13 @@ function guessEditor(): Array { } } - // Last resort, use old-school env vars + // Last resort, use old-school env vars. + // Parse via shell-quote (same as REACT_EDITOR) so the value is split on + // spaces but shell metacharacters are not expanded into a shell command. if (process.env.VISUAL) { - return [process.env.VISUAL]; + return parse(process.env.VISUAL); } else if (process.env.EDITOR) { - return [process.env.EDITOR]; + return parse(process.env.EDITOR); } return []; @@ -116,6 +122,14 @@ export function getValidFilePath( // We use relative paths at Facebook with deterministic builds. // This is why our internal tooling calls React DevTools with absoluteProjectRoots. // If the filename is absolute then we don't need to care about this. + + // Reject paths containing shell metacharacters to prevent CWE-78 OS Command + // Injection. On Windows, file paths are passed through cmd.exe which + // interprets characters like &, |, ; as shell operators. + if (SHELL_METACHARACTERS_RE.test(maybeRelativePath)) { + return null; + } + if (isAbsolute(maybeRelativePath)) { if (existsSync(maybeRelativePath)) { return maybeRelativePath; @@ -161,6 +175,13 @@ export function launchEditor( return; } + // Reject editor binaries containing shell metacharacters to prevent CWE-78. + // On Windows the editor string is passed to cmd.exe /C which would interpret + // operators like & and | as command separators. + if (SHELL_METACHARACTERS_RE.test(editor)) { + return; + } + let args = destructuredArgs; if (lineNumber) {