Files
portal/tools/powershell-destructive.mjs
T
Дмитрий 183733835f harden(m7-floor): PS-алиасы forge+delete (sharp-edges после 1.4)
Строгий sharp-edges-гейт после Task 1.4 вскрыл обход через PowerShell-алиасы:
- forge P-3: `sc`/`cpi`/`ni` (алиасы Set-Content/Copy-Item/New-Item) писали в
  ~/.claude/runtime/.env мимо литеральных глаголов → подделка escape-гранта.
  Закрытие: PS_WRITE_VERB_RE += sc/ac/cpi/copy/mi/move/ni/tee (path-gated, FP только
  с протектед-путём; контроль `sc query` не over-блокируется).
- delete: `del`/`ri`/`rd`/`rmdir`/`erase` -Recurse -Force обходили литеральный
  Remove-Item. Закрытие: PS_CONTENT_BLOCK_RE алиасы для long+short флагов.

154 GREEN (floor + powershell-destructive + enforce-floor + supreme-gate).
Отложено в Фазу 8 §5 (карты покрытия): `&` call-operator, Invoke-Command (icm),
PS sub-expression $(), полная enumeration алиасов — coverage, не структурный класс.
2026-06-08 09:12:38 +03:00

23 lines
1.5 KiB
JavaScript

#!/usr/bin/env node
/**
* powershell-destructive — content-block для PowerShell-tool (V1-PS, правило 8 §4.1).
* PS-нативные глаголы НЕ матчат unix-regex classify-destructive → отдельный набор.
* Дополняет несущий пол: floor-decide зовёт это для name==='PowerShell' (Task 1.4).
* Реоткрытие v3.8 F1: PowerShell-tool был полностью вне scope content-floor.
*/
const PS_CONTENT_BLOCK_RE = [
// sharp-edges (после 1.4): алиасы Remove-Item — ri/rd/rmdir/del/erase. Long-флаги -Recurse/-Force.
/\b(?:Remove-Item|ri|rd|rmdir|del|erase)\b[^\n]*-(?:Recurse|Force)\b/i,
// Short-флаги -r -fo (+те же алиасы). Срабатывает на recurse-токен затем force-токен.
/\b(?:rm|ri|rd|rmdir|del|erase)\b[^\n]*-[a-z]*r[a-z]*\s[^\n]*-[a-z]*f/i,
/\b(?:Invoke-WebRequest|iwr|curl|wget|Invoke-RestMethod|irm)\b/i, // egress
/\b(?:Invoke-Expression|iex)\b/i, // произвольное исполнение
/\bStart-Process\b/i, // запуск интерпретатора/процесса
/\bOut-File\b/i, // запись в файл
/(?:^|[^0-9>&])>{1,2}(?![>&])/, // redirect >/>>
];
export function psContentBlock(command) {
const cmd = String(command || '');
return PS_CONTENT_BLOCK_RE.some((re) => re.test(cmd));
}