feat: initial open marketplace with llm-security, config-audit, ultraplan-local
This commit is contained in:
commit
f93d6abdae
380 changed files with 65935 additions and 0 deletions
54
plugins/llm-security/scanners/lib/bash-normalize.mjs
Normal file
54
plugins/llm-security/scanners/lib/bash-normalize.mjs
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
// bash-normalize.mjs — Normalize bash parameter expansion evasion techniques.
|
||||
//
|
||||
// Attackers can evade command-name matching by inserting shell metacharacters
|
||||
// that are transparent to bash but break regex patterns.
|
||||
//
|
||||
// This module strips these constructs from command names so that downstream
|
||||
// pattern matching sees the canonical form.
|
||||
//
|
||||
// Exported as a shared module — used by pre-bash-destructive.mjs and
|
||||
// pre-install-supply-chain.mjs.
|
||||
|
||||
/**
|
||||
* Normalize bash parameter expansion and quoting evasion in a command string.
|
||||
*
|
||||
* Strips:
|
||||
* - Empty single quotes: '' (e.g., w''get -> wget)
|
||||
* - Empty double quotes: "" (e.g., r""m -> rm)
|
||||
* - Single-char parameter expansion: ${x} -> x (evasion: attacker sets x=x)
|
||||
* - Multi-char parameter expansion: ${ANYTHING} -> '' (unknown value)
|
||||
* - Backslash escapes between word chars, iteratively (c\u\r\l -> curl)
|
||||
* - Backtick subshell with empty/whitespace content
|
||||
*
|
||||
* Does NOT strip:
|
||||
* - Quotes around arguments (only targets empty quotes that split command names)
|
||||
* - $VAR without braces (not an evasion pattern)
|
||||
* - Backslashes before non-word chars (\n, \t, etc.)
|
||||
*
|
||||
* @param {string} cmd - Raw command string
|
||||
* @returns {string} Normalized command string
|
||||
*/
|
||||
export function normalizeBashExpansion(cmd) {
|
||||
if (!cmd || typeof cmd !== 'string') return cmd || '';
|
||||
|
||||
let result = cmd
|
||||
// Strip empty single quotes: w''get -> wget
|
||||
.replace(/''/g, '')
|
||||
// Strip empty double quotes: r""m -> rm
|
||||
.replace(/""/g, '')
|
||||
// Single-char ${x} -> x (evasion: c${u}rl -> curl, assumes x=x)
|
||||
.replace(/\$\{(\w)\}/g, '$1')
|
||||
// Multi-char ${ANYTHING} -> '' (unknown value, strip entirely)
|
||||
.replace(/\$\{[^}]*\}/g, '')
|
||||
// Strip backtick subshell with empty/whitespace content
|
||||
.replace(/`\s*`/g, '');
|
||||
|
||||
// Iteratively strip backslash between word chars (c\u\r\l needs 2 passes)
|
||||
let prev;
|
||||
do {
|
||||
prev = result;
|
||||
result = result.replace(/(\w)\\(\w)/g, '$1$2');
|
||||
} while (result !== prev);
|
||||
|
||||
return result;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue