feat(pre-bash-destructive): T8 — base64-pipe-shell idiom (E9)

Adds BLOCK_RULE for the malware-loader pattern:
  echo|cat|printf <base64-blob> | base64 -d | <shell>

This is a common RCE delivery shape that bypasses static name-matching
gates by encoding the destructive command as a base64 blob. The new
rule fires only when the final pipe target is a shell interpreter
(bash, sh, zsh, dash, ksh) — base64 decoded into jq or any non-shell
consumer remains allowed.

5 new tests in pre-bash-destructive.test.mjs:
- 3 BLOCK cases (echo|base64|bash, printf|base64|sh, cat|base64|zsh)
- 2 FP probes (base64 -d -> jq passes; base64 -d alone passes)

Closes E9 in critical-review-2026-04-20.md.
This commit is contained in:
Kjell Tore Guttormsen 2026-04-30 15:15:29 +02:00
commit 336e4db1b8
2 changed files with 43 additions and 0 deletions

View file

@ -79,6 +79,17 @@ const BLOCK_RULES = [
'strings, which is a common code injection vector. Blocked. ' +
'Refactor to use explicit commands instead.',
},
{
name: 'T8 — base64-pipe-shell idiom (echo BLOB | base64 -d | sh)',
// Matches: echo|cat|printf <base64-blob> | base64 -d | <shell>
// Common malware loader pattern that bypasses static name-matching by
// delivering the destructive command as encoded text.
pattern: /\b(?:echo|cat|printf)\s+[A-Za-z0-9+/=]+\s*\|\s*base64\s+-d\s*\|\s*(?:bash|sh|zsh|dash|ksh)\b/i,
description:
'Decoding a base64 blob and piping it directly into a shell interpreter ' +
'is a remote-code-execution loader pattern. Decode the blob first, ' +
'inspect it, then execute explicitly if safe.',
},
// Policy-defined additional blocked patterns
...getPolicyValue('destructive', 'additional_blocked', []).map(entry => ({
name: entry.name || 'Custom blocked pattern',