- Location
- src/deploy/railway.ts:135
- Finding
- Shell command injection in Railway deployment operations<![CDATA[
## Vulnerability Details
**File Location**: `src/deploy/railway.ts:135-165`; input call sites at `src/commands/deploy.ts:330-374`
**Vulnerability Type**: OS command injection
**Risk Level**: High
### Vulnerable Code
```ts
export function initProject(name?: string): void {
const cmd = name ? `railway init --name "${name}"` : "railway init";
execSync(cmd, { ...EXEC_OPTS, stdio: "inherit" });
}
/** Link the named service so subsequent CLI commands (variables, logs, etc.) target it. */
export function linkService(name: string): void {
execSync(`railway service link ${name}`, {
...EXEC_OPTS,
stdio: ["pipe", "pipe", "pipe"],
});
}
export function setVariable(key: string, value: string): void {
execSync(`railway variables set ${key}="${value}"`, {
...EXEC_OPTS,
stdio: ["pipe", "pipe", "pipe"],
});
}
export function deleteVariable(key: string): void {
execSync(`railway variables delete ${key}`, {
...EXEC_OPTS,
stdio: ["pipe", "pipe", "pipe"],
});
}
```
The environment command performs only minimal parsing:
```ts
const eqIdx = keyValue.indexOf("=");
if (eqIdx === -1) {
output.fatal(
"Invalid format. Use: acp serve deploy railway env set KEY=value"
);
}
const key = keyValue.slice(0, eqIdx);
const value = keyValue.slice(eqIdx + 1);
if (!key) {
output.fatal("Key cannot be empty.");
}
railway.setVariable(key, value);
```
### Technical Analysis
`execSync(string)` executes through a shell. User-controlled environment keys and values, as well as names derived from agent data, are concatenated into shell commands. The code verifies only that a key is non-empty; it does not validate environment-variable syntax or safely encode shell arguments.
Placing a value inside double quotes is insufficient because shells still process command substitution and certain escape sequences within double quotes. The unquoted key and service name have an even broader injection surface.
### Attack Path
1. A user, compromised
...[truncated 966 chars]
- Remediation
- <![CDATA[
## Remediation Suggestions
1. Replace string-based `execSync()` calls with `execFileSync()` or `spawnSync()` and argument arrays:
```ts
execFileSync("railway", ["variables", "set", `${key}=${value}`], {
...EXEC_OPTS,
stdio: ["pipe", "pipe", "pipe"],
});
```
2. Set `shell: false` explicitly.
3. Validate environment keys with:
```regex
^[A-Za-z_][A-Za-z0-9_]*$
```
4. Apply strict length and character policies to project and service names.
5. Pass names as separate arguments rather than attempting shell escaping.
6. Avoid including secrets in command strings because command lines may be exposed to process inspection.
7. Add tests covering quotes, substitutions, semicolons, newlines, redirection characters, and leading option characters.
]]>