escape printed characters to prevent command injection #45
This commit is contained in:
@@ -5,6 +5,12 @@ export class BatchBuilder extends CodeBuilder {
|
|||||||
return '::';
|
return '::';
|
||||||
}
|
}
|
||||||
protected writeStandardOut(text: string): string {
|
protected writeStandardOut(text: string): string {
|
||||||
return `echo ${text}`;
|
return `echo ${escapeForEcho(text)}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function escapeForEcho(text: string) {
|
||||||
|
return text
|
||||||
|
.replace(/&/g, '^&')
|
||||||
|
.replace(/%/g, '%%');
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,6 +5,11 @@ export class ShellBuilder extends CodeBuilder {
|
|||||||
return '#';
|
return '#';
|
||||||
}
|
}
|
||||||
protected writeStandardOut(text: string): string {
|
protected writeStandardOut(text: string): string {
|
||||||
return `echo '${text}'`;
|
return `echo '${escapeForEcho(text)}'`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function escapeForEcho(text: string) {
|
||||||
|
return text
|
||||||
|
.replace(/'/g, '\'\\\'\'');
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,15 +23,37 @@ describe('BatchBuilder', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('writeStandardOut', () => {
|
describe('writeStandardOut', () => {
|
||||||
it('prepends expected', () => {
|
const testData = [
|
||||||
|
{
|
||||||
|
name: 'plain text',
|
||||||
|
text: 'test',
|
||||||
|
expected: 'echo test',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'text with ampersand',
|
||||||
|
text: 'a & b',
|
||||||
|
expected: 'echo a ^& b',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'text with percent sign',
|
||||||
|
text: '90%',
|
||||||
|
expected: 'echo 90%%',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'text with multiple ampersands and percent signs',
|
||||||
|
text: 'Me&you in % ? You & me = 0%',
|
||||||
|
expected: 'echo Me^&you in %% ? You ^& me = 0%%',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
for (const test of testData) {
|
||||||
|
it(test.name, () => {
|
||||||
// arrange
|
// arrange
|
||||||
const text = 'test';
|
|
||||||
const expected = `echo ${text}`;
|
|
||||||
const sut = new BatchBuilderRevealer();
|
const sut = new BatchBuilderRevealer();
|
||||||
// act
|
// act
|
||||||
const actual = sut.writeStandardOut(text);
|
const actual = sut.writeStandardOut(test.text);
|
||||||
// assert
|
// assert
|
||||||
expect(expected).to.equal(actual);
|
expect(test.expected).to.equal(actual);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -23,15 +23,32 @@ describe('ShellBuilder', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('writeStandardOut', () => {
|
describe('writeStandardOut', () => {
|
||||||
it('prepends expected', () => {
|
const testData = [
|
||||||
|
{
|
||||||
|
name: 'plain text',
|
||||||
|
text: 'test',
|
||||||
|
expected: 'echo \'test\'',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'text with single quote',
|
||||||
|
text: 'I\'m not who you think I am',
|
||||||
|
expected: 'echo \'I\'\\\'\'m not who you think I am\'',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'text with multiple single quotes',
|
||||||
|
text: 'I\'m what you\'re',
|
||||||
|
expected: 'echo \'I\'\\\'\'m what you\'\\\'\'re\'',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
for (const test of testData) {
|
||||||
|
it(test.name, () => {
|
||||||
// arrange
|
// arrange
|
||||||
const text = 'test';
|
|
||||||
const expected = `echo '${text}'`;
|
|
||||||
const sut = new ShellBuilderRevealer();
|
const sut = new ShellBuilderRevealer();
|
||||||
// act
|
// act
|
||||||
const actual = sut.writeStandardOut(text);
|
const actual = sut.writeStandardOut(test.text);
|
||||||
// assert
|
// assert
|
||||||
expect(expected).to.equal(actual);
|
expect(test.expected).to.equal(actual);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user