Something went wrong. Try again.
source dump of claude code forked from oppi.li/claude-code
Something went wrong. Try again.
6.2 kB · 185 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186/** * Shared constants for PowerShell cmdlets that execute arbitrary code. * * These lists are consumed by both the permission-engine validators * (powershellSecurity.ts) and the UI suggestion gate (staticPrefix.ts). * Keeping them here avoids duplicating the lists and prevents sync drift * — add a cmdlet once, both consumers pick it up. */
import { CROSS_PLATFORM_CODE_EXEC } from '../permissions/dangerousPatterns.js'import { COMMON_ALIASES } from './parser.js'
/** * Cmdlets that accept a -FilePath (or positional path) and execute the * file's contents as a script. */export const FILEPATH_EXECUTION_CMDLETS = new Set([ 'invoke-command', 'start-job', 'start-threadjob', 'register-scheduledjob',])
/** * Cmdlets where a scriptblock argument executes arbitrary code (not just * filtering/transforming pipeline input like Where-Object). */export const DANGEROUS_SCRIPT_BLOCK_CMDLETS = new Set([ 'invoke-command', 'invoke-expression', 'start-job', 'start-threadjob', 'register-scheduledjob', 'register-engineevent', 'register-objectevent', 'register-wmievent', 'new-pssession', 'enter-pssession',])
/** * Cmdlets that load and execute module/script code. `.psm1` files run * their top-level body on import — same code-execution risk as iex. */export const MODULE_LOADING_CMDLETS = new Set([ 'import-module', 'ipmo', 'install-module', 'save-module', 'update-module', 'install-script', 'save-script',])
/** * Shells and process spawners. Small, stable — add here only for cmdlets * not covered by the validator lists above. */const SHELLS_AND_SPAWNERS = [ 'pwsh', 'powershell', 'cmd', 'bash', 'wsl', 'sh', 'start-process', 'start', 'add-type', 'new-object',] as const
function aliasesOf(targets: ReadonlySet<string>): string[] { return Object.entries(COMMON_ALIASES) .filter(([, target]) => targets.has(target.toLowerCase())) .map(([alias]) => alias)}
/** * Network cmdlets — wildcard rules for these enable exfil/download without * prompt. No legitimate narrow prefix exists. */export const NETWORK_CMDLETS = new Set([ 'invoke-webrequest', 'invoke-restmethod',])
/** * Alias/variable mutation cmdlets — Set-Alias rebinds command resolution, * Set-Variable can poison $PSDefaultParameterValues. checkRuntimeStateManipulation * validator in powershellSecurity.ts independently gates on the permission path. */export const ALIAS_HIJACK_CMDLETS = new Set([ 'set-alias', 'sal', // alias not in COMMON_ALIASES — list explicitly 'new-alias', 'nal', // alias not in COMMON_ALIASES — list explicitly 'set-variable', 'sv', // alias not in COMMON_ALIASES — list explicitly 'new-variable', 'nv', // alias not in COMMON_ALIASES — list explicitly])
/** * WMI/CIM process spawn — Invoke-WmiMethod -Class Win32_Process -Name Create * is a Start-Process equivalent that bypasses checkStartProcess. No legitimate * narrow prefix exists; any invocation can spawn arbitrary processes. * checkWmiProcessSpawn validator gates on the permission path. * (security finding #34) */export const WMI_CIM_CMDLETS = new Set([ 'invoke-wmimethod', 'iwmi', // alias not in COMMON_ALIASES — list explicitly 'invoke-cimmethod',])
/** * Cmdlets in CMDLET_ALLOWLIST with additionalCommandIsDangerousCallback. * * The allowlist auto-allows these for safe args (StringConstant identifiers). * The permission dialog only fires when the callback rejected — i.e. the args * contain a scriptblock, variable, subexpression, etc. Accepting a * `Cmdlet:*` wildcard at that point would match ALL future invocations via * prefix-startsWith, bypassing the callback forever. * `ForEach-Object:*` → `ForEach-Object { Remove-Item -Recurse / }` auto-allows. * * Sync with readOnlyValidation.ts — test/utils/powershell/dangerousCmdlets.test.ts * asserts this set covers every additionalCommandIsDangerousCallback entry. */export const ARG_GATED_CMDLETS = new Set([ 'select-object', 'sort-object', 'group-object', 'where-object', 'measure-object', 'write-output', 'write-host', 'start-sleep', 'format-table', 'format-list', 'format-wide', 'format-custom', 'out-string', 'out-host', // Native executables with callback-gated args (e.g. ipconfig /flushdns // is rejected, ipconfig /all is allowed). Same bypass risk. 'ipconfig', 'hostname', 'route',])
/** * Commands to never suggest as a wildcard prefix in the permission dialog. * * Derived from the validator lists above plus the small static shells list. * Add a cmdlet to the appropriate validator list and it automatically * appears here — no separate maintenance. */export const NEVER_SUGGEST: ReadonlySet<string> = (() => { const core = new Set<string>([ ...SHELLS_AND_SPAWNERS, ...FILEPATH_EXECUTION_CMDLETS, ...DANGEROUS_SCRIPT_BLOCK_CMDLETS, ...MODULE_LOADING_CMDLETS, ...NETWORK_CMDLETS, ...ALIAS_HIJACK_CMDLETS, ...WMI_CIM_CMDLETS, ...ARG_GATED_CMDLETS, // ForEach-Object's -MemberName (positional: `% Delete`) resolves against // the runtime pipeline object — `Get-ChildItem | % Delete` invokes // FileInfo.Delete(). StaticParameterBinder identifies the // PropertyAndMethodSet parameter set, but the set handles both; the arg // is a plain StringConstantExpressionAst with no property/method signal. // Pipeline type inference (upstream OutputType → GetMember) misses ETS // AliasProperty members and has no answer for `$var | %` or external // upstream. Not in ARG_GATED (no allowlist entry to sync with). 'foreach-object', // Interpreters/runners — `node script.js` stops at the file arg and // suggests bare `node:*`, auto-allowing arbitrary code via -e/-p. The // auto-mode classifier strips these rules (isDangerousPowerShellPermission) // but the suggestion gate didn't. Multi-word entries ('npm run') are // filtered out — NEVER_SUGGEST is a single-name lookup on cmd.name. ...CROSS_PLATFORM_CODE_EXEC.filter(p => !p.includes(' ')), ]) return new Set([...core, ...aliasesOf(core)])})()