npm PraisonAI 유틸리티 셸 안전 명령 래퍼 허용 목록 우회(셸 연결을 통해)
게시된 npm 패키지 praisonai에는 소스에 설명된 shell(command) 도우미를 다음과 같이 내보내는 dist/tools/utility-tools.js가 포함되어 있습니다.
``텍스트 쉘 명령 실행(안전한 버전 - 읽기 전용 명령)
도우미는 공백으로 구분된 첫 번째 토큰만 확인하여 안전한 읽기 전용 명령 허용 목록을 적용하려고 시도합니다.
``ts
const safeCommands = ['ls', 'cat', 'head', 'tail', 'wc', 'grep', 'find', 'echo', 'date', 'pwd', 'which'];
const firstWord = command.split(/\s+/)[0];
if (!safeCommands.includes(firstWord)) {
return { 성공: false, 오류: `허용되지 않는 명령: ${firstWord}` };
}
그런 다음 전체 원본 문자열을 노드 child_process.exec()에 전달합니다.
``ts const { stdout, stderr } = wait execAsync(command, { timeout: 5000 });
`exec()`는 셸을 통해 명령을 실행하기 때문에 허용된 명령으로 시작하는 명령 문자열은 허용 목록에 없는 두 번째 명령에 셸 메타 문자를 추가할 수 있습니다. 예를 들어 `printf <marker>` 직접 명령은 거부되지만 `echo ok; printf <marker>`가 허용되고 `printf`를 실행합니다.
이는 도우미의 안전 명령 정책을 우회하고 애플리케이션, 에이전트 또는 통합이 이 도우미를 신뢰도가 낮은 사용자, 프롬프트, 모델 출력 또는 플러그인/도구 입력에 노출할 때 임의의 셸 명령이 PraisonAI 프로세스 권한으로 실행되도록 허용합니다.
PoV는 결정적이며 로컬 전용입니다. npm 패키지만 설치하고 무해한 마커 명령을 실행하며 설치 후 라이브 서비스에 연결하지 않습니다.
## 기술적인 세부사항
`utility-tools.shell()`은 하나의 토큰을 인증하지만 전체 쉘 문자열을 실행합니다.
소스 헤드 구현:
``ts
비동기 함수 내보내기 shell(command: string): Promise<ToolResult<string>> {
// 안전한 읽기 전용 명령만 허용
const safeCommands = ['ls', 'cat', 'head', 'tail', 'wc', 'grep', 'find', 'echo', 'date', 'pwd', 'which'];
const firstWord = command.split(/\s+/)[0];
if (!safeCommands.includes(firstWord)) {
return { 성공: false, 오류: `허용되지 않는 명령: ${firstWord}` };
}
{를 시도해보세요
const { exec } = import('child_process')를 기다립니다;
const { 약속 } = import('util')을 기다립니다;
const execAsync = promisify(exec);
const { stdout, stderr } = wait execAsync(command, { timeout: 5000 });
return { 성공: true, 데이터: stdout || 표준 오류 };
} 잡기(오류: 모두) {
return { 성공: false, 오류: error.message ?? 문자열(오류) };
}
}
게시된 npm:praisonai@1.7.1 dist 파일은 동일한 동작을 유지합니다.
exports.shell = 쉘const firstWord = command.split(/\s+/)[0]if (!safeCommands.includes(firstWord)) ...const { stdout, stderr } = execAsync(command, { timeout: 5000 }) 대기이렇게 하면 정책/파서 차이가 생성됩니다. PraisonAI는 첫 번째 토큰만 확인하는 반면 셸은 전체 문자열을 스크립트로 구문 분석합니다.
도우미는 읽기 전용 명령에 대한 "안전한 버전"으로 코드에 명시적으로 문서화되어 있으며 특정 안전 명령의 허용 목록을 포함합니다. 제어 테스트는 허용 목록에 없는 명령이 차단되도록 의도되었음을 입증합니다. direct printf <marker>는 허용되지 않는 명령: printf를 반환합니다.
동일한 도우미가 'echo ok; 따라서 printf `는 단순히 허용적인 명령 실행기가 아니라 의도된 안전 명령 경계를 우회하는 것입니다.
이는 쉘 실행에 대한 Node의 자체 지침과도 일치합니다. child_process.exec()는 쉘을 통해 실행되며 쉘 메타 문자는 실행되는 명령을 변경할 수 있습니다. 수정 사항은 PraisonAI의 인증 경계가 실제로 실행되는 것과 일치하도록 해야 합니다.
로컬 복제 체크아웃에서 실행:
``배쉬 노드 poc/pov_poc.js 1.7.1
`evidence/pov-npm-1.7.1.json`에서 관찰된 출력 요약:
``json
{
"패키지": "npm:praisonai",
"버전": "1.7.1",
"installedPackageVersion": "1.7.1",
"명령": {
"directDisallowedCommand": "printf poc.7.1",
"benignAllowedCommand": "echo poc",
"chainedBypassCommand": "echo poc; printf poc.7.1"
},
"컨트롤": {
"directDisallowedRejected": 사실,
"benignAllowedAccepted": 사실,
"patchedControlRejectsChainedShell": 참
},
"관찰": {
"directDisallowed": {
"성공": 거짓,
"오류": "허용되지 않는 명령: printf"
},
"chainedBypass": {
"성공": 사실,
"data": "poc\npoc.7.1"
}
},
"취약한": 사실
}
해석:
printf가 safeCommands에 없기 때문에 직접 printf <marker>가 거부됩니다.에코...가 허용됩니다.
-에코 ...; printf <marker>는 첫 번째 토큰이 echo이기 때문에 허용됩니다.printf 명령을 실행합니다.에코를 허용합니다.PoV는 무해한 마커 출력만 사용합니다. 시스템 파일을 읽거나, 환경 변수를 유출하거나, 외부 서비스를 호출하거나, 파괴적인 명령을 실행하지 않습니다.
위의 PoV 섹션에는 로컬 재생 명령, 입력 및 결정적인 출력이 포함됩니다.
신뢰도가 낮은 사용자, 프롬프트, 모델 출력, 플러그인 또는 도구 입력이 utility-tools.shell()에 전달된 명령 문자열에 영향을 미칠 수 있는 경우 안전 명령 허용 목록은 실행을 의도된 읽기 전용 명령으로 제한하지 않습니다. 공격자는 허용된 첫 번째 토큰 뒤에 임의의 셸 명령을 추가하고 PraisonAI 프로세스 권한으로 실행할 수 있습니다.
구체적인 결과는 포함 애플리케이션 및 프로세스 권한에 따라 다르지만 다음이 포함될 수 있습니다.
이 보고서는 npm PraisonAI가 이 도우미를 인증되지 않은 기본 네트워크 서비스로 노출한다고 주장하지 않습니다. 이는 제공된 npm 하위 경로의 라이브러리 수준 안전 명령 래퍼 우회입니다.
권장 심각도: 높음.
근거:
AC: 허용된 명령으로 시작하는 단일 명령 문자열이면 충분합니다.UI: 명령이 도우미에 도달하면 더 이상 운영자 상호 작용이 필요하지 않습니다.S: 영향은 PraisonAI 호스팅 프로세스와 호스트 컨텍스트 내에 있습니다.C/I/A: 임의의 셸 명령은 프로세스 권한에 따라 기밀성, 무결성 및 가용성에 영향을 미칠 수 있습니다.관리자가 직접 로컬 라이브러리 사용에만 점수를 매긴다면 'AV:L'이 합리적일 수 있습니다. 배포가 인증되지 않은 에이전트/도구 엔드포인트를 통해 이 도우미를 노출하는 경우 'PR:N'이 합리적일 수 있습니다.
정책 확인 문자열을 셸에 전달하지 마세요.
권장사항:
exec(command)를 execFile() 또는 spawn(command, args, { shell: false })로 바꾸세요.{ command, args }를 전달하도록 요구하거나 정책 확인 전에 셸 인식 파서를 사용하여 셸 문자열을 argv로 구문 분석합니다.;, &&, ||, |, 백틱, $(), 리디렉션, 개행)를 거부합니다.printf marker, echo ok; 동안 echo ok가 허용됨을 증명하는 회귀 테스트를 추가합니다. printf 마커, echo ok && printf 마커 및 echo ok | printf marker는 거부됩니다.이 도우미를 공개할 의도가 아닌 경우 지원되는 공개 API 경로만 노출하는 패키지 '내보내기' 맵을 추가하는 것도 고려해 보세요.
MervinPraison/PraisonAInpmpraisonaisrc/praisonai-ts/src/tools/utility-tools.tsnode_modules/praisonai/dist/tools/utility-tools.js1.7.1origin/main의 src/praisonai-ts/package.json: praisonai 1.7.1제안된 영향 범위:
``텍스트 npm:praisonai >= 1.5.1, <= 1.7.1
게시된 모든 npm '1.x' 버전은 로컬로 스윕되었습니다.
- `1.0.0`~`1.5.0`: `dist/tools/utility-tools.js`가 테스트된 패키지에 없습니다.
- `1.5.1`, `1.5.2`, `1.5.3`, `1.5.4`, `1.6.0`, `1.7.0`, `1.7.1`: 취약합니다.
npm 패키지에는 `exports` 맵이 없으며 `files` 목록에 `dist`를 제공하므로 영향을 받는 도우미를 패키지 하위 경로로 가져올 수 있습니다.
``js
const { shell } = require("praisonai/dist/tools/utility-tools.js");
루트 패키지 진입점은 이 도우미를 직접 다시 내보내는 것으로 나타나지 않습니다. 이 보고서의 범위는 제공된 npm 하위 경로와 이를 생성하는 TypeScript 소스로 지정됩니다.
보이는 PraisonAI 권고와 이전 제출이 확인되었습니다. 가장 가까운 알려진 문제는 인접하지만 별개입니다.
GHSA-vjv9-7m7j-h833은 src/cli/features/sandbox-executor.ts의 npm TypeScript SandboxExecutor.allowedCommands를 다룹니다. 여기서 호출자 제공 허용 목록은 spawn("sh", ["-c", command]) 전에 확인됩니다.src/tools/utility-tools.ts의 npm TypeScript utility-tools.shell()을 다룹니다. 여기서 내장된 '안전한 읽기 전용 명령' 허용 목록은 child_process.exec(command) 전에 확인됩니다.execute_command, run_python(), 메모리 후크 및 하위 프로세스 샌드박스 코드와 같은 다양한 패키지, 파일 및 실행 경로를 다룹니다.이는 동일한 성숙한 허용 목록/셸 파서 클래스의 형제 호출 사이트 변형이지만 이전 npm SandboxExecutor 권고와 동일한 기능, 정책 표면, 영향을 받는 버전 범위 또는 제공된 가져오기 경로가 아닙니다.
왜 이 VPI인가 (설명가능 · 실험적)
VPI 산정 기준
| 영향도 | 88.00 |
| 악용 신호(추가 악용신호 없음) | ×1.00 |
| VPI | 88.00 |
VPI 공식 vpi-v1 기준