mirror of
https://github.com/AikidoSec/safe-chain.git
synced 2026-05-26 12:10:49 +00:00
Fix command injection
This commit is contained in:
parent
8ffb0191f5
commit
41bf3252d9
11 changed files with 116 additions and 29 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
import { execSync, spawnSync } from "child_process";
|
import { spawnSync } from "child_process";
|
||||||
import * as os from "os";
|
import * as os from "os";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
|
|
||||||
|
|
@ -26,14 +26,6 @@ export function doesExecutableExistOnSystem(executableName) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function execAndGetOutput(command, shell) {
|
|
||||||
try {
|
|
||||||
return execSync(command, { encoding: "utf8", shell }).trim();
|
|
||||||
} catch (error) {
|
|
||||||
throw new Error(`Command failed: ${command}. Error: ${error.message}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function removeLinesMatchingPattern(filePath, pattern) {
|
export function removeLinesMatchingPattern(filePath, pattern) {
|
||||||
if (!fs.existsSync(filePath)) {
|
if (!fs.existsSync(filePath)) {
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import {
|
import {
|
||||||
addLineToFile,
|
addLineToFile,
|
||||||
doesExecutableExistOnSystem,
|
doesExecutableExistOnSystem,
|
||||||
execAndGetOutput,
|
|
||||||
removeLinesMatchingPattern,
|
removeLinesMatchingPattern,
|
||||||
} from "../helpers.js";
|
} from "../helpers.js";
|
||||||
|
import { execSync } from "child_process";
|
||||||
|
|
||||||
const shellName = "Bash";
|
const shellName = "Bash";
|
||||||
const executableName = "bash";
|
const executableName = "bash";
|
||||||
|
|
@ -14,7 +14,7 @@ function isInstalled() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function teardown() {
|
function teardown() {
|
||||||
const startupFile = execAndGetOutput(startupFileCommand, executableName);
|
const startupFile = getStartupFile();
|
||||||
|
|
||||||
// Removes all aliases starting with "alias npm=", "alias npx=", or "alias yarn="
|
// Removes all aliases starting with "alias npm=", "alias npx=", or "alias yarn="
|
||||||
// This will remove the safe-chain aliases for npm, npx, and yarn commands.
|
// This will remove the safe-chain aliases for npm, npx, and yarn commands.
|
||||||
|
|
@ -24,7 +24,7 @@ function teardown() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function setup(tools) {
|
function setup(tools) {
|
||||||
const startupFile = execAndGetOutput(startupFileCommand, executableName);
|
const startupFile = getStartupFile();
|
||||||
teardown();
|
teardown();
|
||||||
|
|
||||||
for (const { tool, aikidoCommand } of tools) {
|
for (const { tool, aikidoCommand } of tools) {
|
||||||
|
|
@ -37,6 +37,19 @@ function setup(tools) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getStartupFile() {
|
||||||
|
try {
|
||||||
|
return execSync(startupFileCommand, {
|
||||||
|
encoding: "utf8",
|
||||||
|
shell: executableName,
|
||||||
|
}).trim();
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(
|
||||||
|
`Command failed: ${startupFileCommand}. Error: ${error.message}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: shellName,
|
name: shellName,
|
||||||
isInstalled,
|
isInstalled,
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ describe("Bash shell integration", () => {
|
||||||
// Mock the helpers module
|
// Mock the helpers module
|
||||||
mock.module("../helpers.js", {
|
mock.module("../helpers.js", {
|
||||||
namedExports: {
|
namedExports: {
|
||||||
execAndGetOutput: () => mockStartupFile,
|
|
||||||
doesExecutableExistOnSystem: () => true,
|
doesExecutableExistOnSystem: () => true,
|
||||||
addLineToFile: (filePath, line) => {
|
addLineToFile: (filePath, line) => {
|
||||||
if (!fs.existsSync(filePath)) {
|
if (!fs.existsSync(filePath)) {
|
||||||
|
|
@ -33,6 +32,13 @@ describe("Bash shell integration", () => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Mock child_process execSync
|
||||||
|
mock.module("child_process", {
|
||||||
|
namedExports: {
|
||||||
|
execSync: () => mockStartupFile,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
// Import bash module after mocking
|
// Import bash module after mocking
|
||||||
bash = (await import("./bash.js")).default;
|
bash = (await import("./bash.js")).default;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import {
|
import {
|
||||||
addLineToFile,
|
addLineToFile,
|
||||||
doesExecutableExistOnSystem,
|
doesExecutableExistOnSystem,
|
||||||
execAndGetOutput,
|
|
||||||
removeLinesMatchingPattern,
|
removeLinesMatchingPattern,
|
||||||
} from "../helpers.js";
|
} from "../helpers.js";
|
||||||
|
import { execSync } from "child_process";
|
||||||
|
|
||||||
const shellName = "Fish";
|
const shellName = "Fish";
|
||||||
const executableName = "fish";
|
const executableName = "fish";
|
||||||
|
|
@ -14,7 +14,7 @@ function isInstalled() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function teardown() {
|
function teardown() {
|
||||||
const startupFile = execAndGetOutput(startupFileCommand, executableName);
|
const startupFile = getStartupFile();
|
||||||
|
|
||||||
// Removes all aliases starting with "alias npm=", "alias npx=", or "alias yarn="
|
// Removes all aliases starting with "alias npm=", "alias npx=", or "alias yarn="
|
||||||
// This will remove the safe-chain aliases for npm, npx, and yarn commands.
|
// This will remove the safe-chain aliases for npm, npx, and yarn commands.
|
||||||
|
|
@ -24,7 +24,7 @@ function teardown() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function setup(tools) {
|
function setup(tools) {
|
||||||
const startupFile = execAndGetOutput(startupFileCommand, executableName);
|
const startupFile = getStartupFile();
|
||||||
teardown();
|
teardown();
|
||||||
|
|
||||||
for (const { tool, aikidoCommand } of tools) {
|
for (const { tool, aikidoCommand } of tools) {
|
||||||
|
|
@ -37,6 +37,19 @@ function setup(tools) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getStartupFile() {
|
||||||
|
try {
|
||||||
|
return execSync(startupFileCommand, {
|
||||||
|
encoding: "utf8",
|
||||||
|
shell: executableName,
|
||||||
|
}).trim();
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(
|
||||||
|
`Command failed: ${startupFileCommand}. Error: ${error.message}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: shellName,
|
name: shellName,
|
||||||
isInstalled,
|
isInstalled,
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ describe("Fish shell integration", () => {
|
||||||
// Mock the helpers module
|
// Mock the helpers module
|
||||||
mock.module("../helpers.js", {
|
mock.module("../helpers.js", {
|
||||||
namedExports: {
|
namedExports: {
|
||||||
execAndGetOutput: () => mockStartupFile,
|
|
||||||
doesExecutableExistOnSystem: () => true,
|
doesExecutableExistOnSystem: () => true,
|
||||||
addLineToFile: (filePath, line) => {
|
addLineToFile: (filePath, line) => {
|
||||||
if (!fs.existsSync(filePath)) {
|
if (!fs.existsSync(filePath)) {
|
||||||
|
|
@ -33,6 +32,13 @@ describe("Fish shell integration", () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Mock child_process execSync
|
||||||
|
mock.module("child_process", {
|
||||||
|
namedExports: {
|
||||||
|
execSync: () => mockStartupFile,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
// Import fish module after mocking
|
// Import fish module after mocking
|
||||||
fish = (await import("./fish.js")).default;
|
fish = (await import("./fish.js")).default;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import {
|
import {
|
||||||
addLineToFile,
|
addLineToFile,
|
||||||
doesExecutableExistOnSystem,
|
doesExecutableExistOnSystem,
|
||||||
execAndGetOutput,
|
|
||||||
removeLinesMatchingPattern,
|
removeLinesMatchingPattern,
|
||||||
} from "../helpers.js";
|
} from "../helpers.js";
|
||||||
|
import { execSync } from "child_process";
|
||||||
|
|
||||||
const shellName = "PowerShell Core";
|
const shellName = "PowerShell Core";
|
||||||
const executableName = "pwsh";
|
const executableName = "pwsh";
|
||||||
|
|
@ -14,7 +14,7 @@ function isInstalled() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function teardown() {
|
function teardown() {
|
||||||
const startupFile = execAndGetOutput(startupFileCommand, executableName);
|
const startupFile = getStartupFile();
|
||||||
|
|
||||||
// Removes all aliases starting with "Set-Alias npm=", "Set-Alias npx=", or "Set-Alias yarn="
|
// Removes all aliases starting with "Set-Alias npm=", "Set-Alias npx=", or "Set-Alias yarn="
|
||||||
// This will remove the safe-chain aliases for npm, npx, and yarn commands.
|
// This will remove the safe-chain aliases for npm, npx, and yarn commands.
|
||||||
|
|
@ -24,7 +24,7 @@ function teardown() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function setup(tools) {
|
function setup(tools) {
|
||||||
const startupFile = execAndGetOutput(startupFileCommand, executableName);
|
const startupFile = getStartupFile();
|
||||||
teardown();
|
teardown();
|
||||||
|
|
||||||
for (const { tool, aikidoCommand } of tools) {
|
for (const { tool, aikidoCommand } of tools) {
|
||||||
|
|
@ -37,6 +37,19 @@ function setup(tools) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getStartupFile() {
|
||||||
|
try {
|
||||||
|
return execSync(startupFileCommand, {
|
||||||
|
encoding: "utf8",
|
||||||
|
shell: executableName,
|
||||||
|
}).trim();
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(
|
||||||
|
`Command failed: ${startupFileCommand}. Error: ${error.message}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: shellName,
|
name: shellName,
|
||||||
isInstalled,
|
isInstalled,
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ describe("PowerShell Core shell integration", () => {
|
||||||
// Mock the helpers module
|
// Mock the helpers module
|
||||||
mock.module("../helpers.js", {
|
mock.module("../helpers.js", {
|
||||||
namedExports: {
|
namedExports: {
|
||||||
execAndGetOutput: () => mockStartupFile,
|
|
||||||
doesExecutableExistOnSystem: () => true,
|
doesExecutableExistOnSystem: () => true,
|
||||||
addLineToFile: (filePath, line) => {
|
addLineToFile: (filePath, line) => {
|
||||||
if (!fs.existsSync(filePath)) {
|
if (!fs.existsSync(filePath)) {
|
||||||
|
|
@ -33,6 +32,13 @@ describe("PowerShell Core shell integration", () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Mock child_process execSync
|
||||||
|
mock.module("child_process", {
|
||||||
|
namedExports: {
|
||||||
|
execSync: () => mockStartupFile,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
// Import powershell module after mocking
|
// Import powershell module after mocking
|
||||||
powershell = (await import("./powershell.js")).default;
|
powershell = (await import("./powershell.js")).default;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import {
|
import {
|
||||||
addLineToFile,
|
addLineToFile,
|
||||||
doesExecutableExistOnSystem,
|
doesExecutableExistOnSystem,
|
||||||
execAndGetOutput,
|
|
||||||
removeLinesMatchingPattern,
|
removeLinesMatchingPattern,
|
||||||
} from "../helpers.js";
|
} from "../helpers.js";
|
||||||
|
import { execSync } from "child_process";
|
||||||
|
|
||||||
const shellName = "Windows PowerShell";
|
const shellName = "Windows PowerShell";
|
||||||
const executableName = "powershell";
|
const executableName = "powershell";
|
||||||
|
|
@ -14,7 +14,7 @@ function isInstalled() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function teardown() {
|
function teardown() {
|
||||||
const startupFile = execAndGetOutput(startupFileCommand, executableName);
|
const startupFile = getStartupFile();
|
||||||
|
|
||||||
// Removes all aliases starting with "Set-Alias npm=", "Set-Alias npx=", or "Set-Alias yarn="
|
// Removes all aliases starting with "Set-Alias npm=", "Set-Alias npx=", or "Set-Alias yarn="
|
||||||
// This will remove the safe-chain aliases for npm, npx, and yarn commands.
|
// This will remove the safe-chain aliases for npm, npx, and yarn commands.
|
||||||
|
|
@ -24,7 +24,7 @@ function teardown() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function setup(tools) {
|
function setup(tools) {
|
||||||
const startupFile = execAndGetOutput(startupFileCommand, executableName);
|
const startupFile = getStartupFile();
|
||||||
teardown();
|
teardown();
|
||||||
|
|
||||||
for (const { tool, aikidoCommand } of tools) {
|
for (const { tool, aikidoCommand } of tools) {
|
||||||
|
|
@ -37,6 +37,19 @@ function setup(tools) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getStartupFile() {
|
||||||
|
try {
|
||||||
|
return execSync(startupFileCommand, {
|
||||||
|
encoding: "utf8",
|
||||||
|
shell: executableName,
|
||||||
|
}).trim();
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(
|
||||||
|
`Command failed: ${startupFileCommand}. Error: ${error.message}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: shellName,
|
name: shellName,
|
||||||
isInstalled,
|
isInstalled,
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ describe("Windows PowerShell shell integration", () => {
|
||||||
// Mock the helpers module
|
// Mock the helpers module
|
||||||
mock.module("../helpers.js", {
|
mock.module("../helpers.js", {
|
||||||
namedExports: {
|
namedExports: {
|
||||||
execAndGetOutput: () => mockStartupFile,
|
|
||||||
doesExecutableExistOnSystem: () => true,
|
doesExecutableExistOnSystem: () => true,
|
||||||
addLineToFile: (filePath, line) => {
|
addLineToFile: (filePath, line) => {
|
||||||
if (!fs.existsSync(filePath)) {
|
if (!fs.existsSync(filePath)) {
|
||||||
|
|
@ -33,6 +32,13 @@ describe("Windows PowerShell shell integration", () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Mock child_process execSync
|
||||||
|
mock.module("child_process", {
|
||||||
|
namedExports: {
|
||||||
|
execSync: () => mockStartupFile,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
// Import windowsPowershell module after mocking
|
// Import windowsPowershell module after mocking
|
||||||
windowsPowershell = (await import("./windowsPowershell.js")).default;
|
windowsPowershell = (await import("./windowsPowershell.js")).default;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import {
|
import {
|
||||||
addLineToFile,
|
addLineToFile,
|
||||||
doesExecutableExistOnSystem,
|
doesExecutableExistOnSystem,
|
||||||
execAndGetOutput,
|
|
||||||
removeLinesMatchingPattern,
|
removeLinesMatchingPattern,
|
||||||
} from "../helpers.js";
|
} from "../helpers.js";
|
||||||
|
import { execSync } from "child_process";
|
||||||
|
|
||||||
const shellName = "Zsh";
|
const shellName = "Zsh";
|
||||||
const executableName = "zsh";
|
const executableName = "zsh";
|
||||||
|
|
@ -14,7 +14,7 @@ function isInstalled() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function teardown() {
|
function teardown() {
|
||||||
const startupFile = execAndGetOutput(startupFileCommand, executableName);
|
const startupFile = getStartupFile();
|
||||||
|
|
||||||
// Removes all aliases starting with "alias npm=", "alias npx=", or "alias yarn="
|
// Removes all aliases starting with "alias npm=", "alias npx=", or "alias yarn="
|
||||||
// This will remove the safe-chain aliases for npm, npx, and yarn commands.
|
// This will remove the safe-chain aliases for npm, npx, and yarn commands.
|
||||||
|
|
@ -24,7 +24,7 @@ function teardown() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function setup(tools) {
|
function setup(tools) {
|
||||||
const startupFile = execAndGetOutput(startupFileCommand, executableName);
|
const startupFile = getStartupFile();
|
||||||
teardown();
|
teardown();
|
||||||
|
|
||||||
for (const { tool, aikidoCommand } of tools) {
|
for (const { tool, aikidoCommand } of tools) {
|
||||||
|
|
@ -37,6 +37,19 @@ function setup(tools) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getStartupFile() {
|
||||||
|
try {
|
||||||
|
return execSync(startupFileCommand, {
|
||||||
|
encoding: "utf8",
|
||||||
|
shell: executableName,
|
||||||
|
}).trim();
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(
|
||||||
|
`Command failed: ${startupFileCommand}. Error: ${error.message}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: shellName,
|
name: shellName,
|
||||||
isInstalled,
|
isInstalled,
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ describe("Zsh shell integration", () => {
|
||||||
// Mock the helpers module
|
// Mock the helpers module
|
||||||
mock.module("../helpers.js", {
|
mock.module("../helpers.js", {
|
||||||
namedExports: {
|
namedExports: {
|
||||||
execAndGetOutput: () => mockStartupFile,
|
|
||||||
doesExecutableExistOnSystem: () => true,
|
doesExecutableExistOnSystem: () => true,
|
||||||
addLineToFile: (filePath, line) => {
|
addLineToFile: (filePath, line) => {
|
||||||
if (!fs.existsSync(filePath)) {
|
if (!fs.existsSync(filePath)) {
|
||||||
|
|
@ -33,6 +32,13 @@ describe("Zsh shell integration", () => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Mock child_process execSync
|
||||||
|
mock.module("child_process", {
|
||||||
|
namedExports: {
|
||||||
|
execSync: () => mockStartupFile,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
// Import zsh module after mocking
|
// Import zsh module after mocking
|
||||||
zsh = (await import("./zsh.js")).default;
|
zsh = (await import("./zsh.js")).default;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue