react-doctor/command-execution-input-risk
Passing caller-controlled input into a shell command lets an attacker run arbitrary commands on your server (remote code execution).
- Category: Security
- Severity: error
- Source:
oxlint-plugin-react-doctor - Framework: global
- Enabled when: production script source files (.js/.ts/.tsx/.py/.php); tests, build/scripts, docs, generated, and repo dev-tooling (tools/, scripts/, management/commands, build/gulpfile/gruntfile) skipped
- Tags: security-scan
- Default: Enabled
Validation prompt
Use this to decide whether a fired diagnostic is real or a false positive.
Fires in production script source (.js/.ts/.tsx/.py/.php) when a command-execution primitive is called with caller-shaped input nearby in the same call. Sinks: bare exec/execSync/spawn/spawnSync/system/passthru/proc_open/shell_exec (method calls like regex.exec(...) or store.query.exec(...) are excluded), or os.system/subprocess.run|Popen|call/child_process/cp.exec/spawn…. It fires only when, within the call's own argument list (~220 chars, not bleeding past the closing )), it also sees req./request./params./query./body./searchParams/PHP $_GET/$_POST/$_REQUEST, an explicit shell=true/shell: true, or a Python f-string interpolation like f'… {value} …'. FALSE POSITIVE to suppress: a fixed or argv-array command whose only dynamic value is trusted, non-request data (a constant, validated, or allowlisted value) — the request token / f'{…}' / shell=true is what trips it, so confirm the interpolated value truly derives from an external caller. Repo tooling (tools/, scripts/, management/commands/, build/gulpfile/gruntfile) is already exempt as argv-driven, not web-facing.
Fix prompt
Use this once validation confirms the diagnostic is real.
Never build a shell command from caller input. Use the array form with a fixed executable and pass arguments as a list (execFile('convert', [safeName]), spawn(cmd, argsArray), Python subprocess.run([...], shell=False)) so no shell parses the input, and remove shell: true/shell=True. Validate every dynamic argument against a strict allowlist, reject shell metacharacters, and resolve and bound any filenames or paths. Prefer a native library API over shelling out.
Related rules
More Security rules from the rules reference:
react-doctor/cors-cookie-trust-risk: Combining credentialed CORS with a wildcard or less-trusted origin, or scoping auth cookies to a parent domain, lets other sites or subdomains ride a user's session.react-doctor/dangerous-html-sink: Passing user- or request-derived data into an HTML sink like `dangerouslySetInnerHTML` or `innerHTML` without sanitizing it allows cross-site scripting.react-doctor/firebase-client-owned-authz-field: When the client writes ownership or role fields (`ownerId`, `orgId`, `role`, `isAdmin`) to Firebase/Supabase, an attacker can forge them and grant themselves access.react-doctor/firebase-permissive-rules: A Firebase rule of `if true` or `if request.auth != null` leaves data open to everyone (or to every signed-in user), treating sign-in as authorization and exposing other users' data.react-doctor/firebase-query-filter-as-auth: Relying on a client-side Firestore `.where('userId', '==', …)` filter for access control is unsafe, because a client can drop the filter and read everyone's data.