Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .github/workflows/security-scan.yml
Original file line number Diff line number Diff line change
@@ -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
27 changes: 24 additions & 3 deletions packages/react-devtools-core/src/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -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':
Expand Down Expand Up @@ -97,11 +101,13 @@ function guessEditor(): Array<string> {
}
}

// 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 [];
Expand All @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down