They often assume quoting is enough. In reality, double quotes do not stop command substitution or embedded language evaluation when a tool builds commands from data. The safer model is to prevent untrusted input from becoming code at all, rather than trying to escape every dangerous character.
Why This Matters for Security Teams
Build tooling is often treated as a safe translation layer, but shell quoting does not turn untrusted data into harmless text if the tool later hands that data to a shell, parser, or embedded interpreter. That is why this issue keeps surfacing in CI, package build scripts, release automation, and developer tooling. The problem is not just injection in the classic sense; it is misplaced trust in escaping as a control.
Security teams also tend to review the final shell command instead of the full data flow that created it. Once a build system concatenates flags, file names, or environment values into executable text, quoting rules become context-dependent and brittle. NIST’s Cybersecurity Framework 2.0 emphasises managing implementation risk across the full lifecycle, which fits this problem better than point fixes. In practice, many teams discover shell parsing flaws only after a pipeline has already executed attacker-controlled input, not during code review or test design.
How It Works in Practice
The safe mental model is simple: do not let untrusted input become code. In build tools, that means preferring APIs that pass arguments as structured arrays or typed fields, rather than building one command string for a shell to interpret. Double quotes only protect against some word splitting. They do not reliably stop command substitution, nested evaluation, or language-specific expansion if another parser is involved.
This becomes especially important in environments that mix shell, YAML, JSON, Makefiles, Python wrappers, JavaScript build scripts, or CI expression languages. Each layer can reinterpret characters differently. An input that looks quoted at one layer may still be expanded later. The safer pattern is to treat shell execution as a last resort and keep data and code separate until the final system call.
Practitioners usually reduce risk by combining several controls:
- Use argument arrays or exec-style APIs instead of shell interpolation.
- Apply allowlists for values such as file names, modes, and target names.
- Reject shell metacharacters rather than trying to escape every character.
- Keep secrets out of command lines, because process lists and logs can expose them.
NHIMG research shows why this matters operationally: The Ultimate Guide to Non-Human Identities notes that 96% of organisations store secrets outside secrets managers in vulnerable locations such as code, config files, and CI/CD tools. That same pattern often appears in build systems where quoted values and inline secrets are mixed into commands. These controls tend to break down when a build chain spans multiple interpreters, because each stage can re-evaluate the same string under different rules.
Common Variations and Edge Cases
Tighter command construction often increases developer friction, requiring organisations to balance safety against convenience and compatibility. That tradeoff is most visible in legacy build scripts, cross-platform tooling, and plugin ecosystems where command strings are deeply embedded.
There is no universal standard for shell quoting that works across Bash, sh, PowerShell, Make, and application-specific template engines. Best practice is evolving toward context-aware execution boundaries, not universal escaping. That is why a command that is safe in one environment can become unsafe after a seemingly minor refactor, such as moving from a direct subprocess call to a helper that invokes a shell for logging or portability.
Edge cases also appear when build tools call other tools that accept their own mini-languages. For example, a quoted argument may still be parsed by an inner interpreter, or a seemingly safe variable may be expanded by the CI runner before the shell ever sees it. The real control is not better quoting syntax. It is preventing data from crossing into executable context unless it has been explicitly validated and reduced to a narrow, expected form. NHIMG’s Schneider Electric credentials breach and Nx Package Attack — 2,300+ Credentials Leaked both underscore how quickly build and supply-chain workflows can turn small trust mistakes into large exposure.
Standards & Framework Alignment
This section maps relevant standards and security frameworks to the operational risks and controls described in this guidance.
OWASP Non-Human Identity Top 10, OWASP Agentic AI Top 10 and CSA MAESTRO address the attack and risk surface, while NIST AI RMF and NIST CSF 2.0 set the governance and control requirements practitioners need to meet.
| Framework | Control / Reference | Relevance |
|---|---|---|
| OWASP Non-Human Identity Top 10 | NHI-04 | Shell injection in build tools often exposes NHI secrets and tokens. |
| OWASP Agentic AI Top 10 | A-04 | Tool invocation by agents or automations must not execute untrusted data as code. |
| CSA MAESTRO | M1 | Build pipelines are autonomous execution paths that need strict trust boundaries. |
| NIST AI RMF | This is a governance and risk issue around unsafe system behavior in automation. | |
| NIST CSF 2.0 | PR.DS-5 | Command injection often leaks or mishandles data and secrets in pipelines. |
Protect sensitive data in build flows by removing secrets from logs, commands, and environment variables.