Bash 도구

셸 스냅샷, 명령 빌드 파이프라인, 21개 보안 검증기, 샌드박싱, 백그라운드 실행까지.

01

개요

Bash 도구는 Claude Code에서 가장 강력하고 동시에 가장 복잡한 도구입니다. 사용자의 로컬 셸에서 임의의 명령을 실행할 수 있다는 것은 곧 보안, 격리, 출력 처리, 권한 제어가 모두 한 곳에 수렴한다는 뜻입니다. 이 레슨에서는 명령이 입력되고 실행되어 결과가 반환되기까지의 전체 파이프라인을 소스 레벨에서 분석합니다.

다루는 소스 파일: tools/BashTool/utils/bash/utils/shell/utils/sandbox/

모델에 보이는 입력 파라미터:

추가 제어 필드: run_in_background는 공개 도구 표면에서도 쓰일 수 있는 실행 제어 필드이고, dangerouslyDisableSandbox 같은 값은 내부 실행 경로에서만 덧붙는 항목입니다. Bash 도구를 설명할 때는 모델이 요청할 수 있는 공개 입력과, 런타임이 내부적으로 추가하는 제어 입력을 구분해서 봐야 합니다.

정규화된 출력 필드:

02

입력/출력 스키마 (Input/Output Schema)

공개 입력 스키마

모델이 호출할 수 있는 Bash 도구 표면은 Zod strictObject로 정의됩니다. 선언되지 않은 필드는 자동 거부됩니다.

파라미터 타입 필수 설명
command string 필수 실행할 셸 명령 문자열. 6단계 빌드 파이프라인을 거쳐 실제 셸에 전달됨
timeout number 선택 밀리초 단위 타임아웃. 최대 600,000ms (10분). 미지정 시 기본 타임아웃 적용
description string 선택 명령에 대한 자연어 설명. UI 표시와 권한 판단에 활용됨

다만 실제 런타임은 이 공개 입력을 그대로 실행기에 넘기지 않습니다. 백그라운드 실행, 샌드박스 우회 같은 내부 플래그가 덧붙은 내부 입력 스키마가 따로 있으며, 이는 UI 이벤트나 런타임 제어 경로에서 채워집니다.

출력 필드

도구 실행 결과는 다음 필드로 정규화됩니다. 종료 코드는 내부에서 의미적으로 해석되지만, lesson 관점에서 중요한 공개 출력 표면은 아래 네 가지입니다.

필드 타입 설명
stdout string 표준 출력. 후처리 단계에서 잘림, 힌트 제거, 이미지 감지 등이 적용될 수 있음
stderr string 표준 에러. 다만 기본 셸 실행 경로에서는 2>&1 병합으로 거의 항상 빈 문자열에 가깝다
interrupted boolean 사용자 또는 타임아웃에 의한 중단 여부
backgroundTaskId string? 백그라운드 실행 시에만 반환되는 태스크 식별자
// Bash 도구 공개 입력 스키마
const publicInputSchema = z.strictObject({
  command: z.string(),                           // 필수: 셸 명령
  timeout: z.number().max(600_000).optional(),   // 선택: 타임아웃 (ms)
  description: z.string().optional(),             // 선택: 자연어 설명
})

// 확장 입력 스키마는 공개 입력 위에 제어 필드를 덧붙인다
const internalInputSchema = publicInputSchema.extend({
  run_in_background: z.boolean().optional(),     // 선택: 백그라운드 실행
  dangerouslyDisableSandbox: z.boolean().optional(),
})

// 출력 타입
type BashOutput = {
  stdout: string
  stderr: string
  interrupted: boolean       // 중단 여부
  backgroundTaskId?: string  // 백그라운드 시에만
}
주의사항

Bash 결과 표면에는 stdoutstderr 필드가 모두 존재하지만, 기본 셸 프로바이더 경로에서는 2>&1 병합이 걸려 stderr가 거의 항상 비어 있습니다. 그래서 오류 메시지도 실제로는 stdout에서 읽는 쪽이 맞습니다. 종료 코드는 별도 필드로 단순 노출되기보다, 아래의 의미적 해석 단계에서 사용됩니다.

03

셸 스냅샷 시스템

Bash 도구가 명령을 실행하려면 먼저 사용자의 셸 환경을 재현해야 합니다. 이를 위해 세션당 한 번 셸 스냅샷을 생성하여 ~/.claude/shell-snapshots/에 저장합니다.

스냅샷 생성 과정:

  1. 사용자 설정 파일 캡처.bashrc, .zshrc, .profile 등에서 환경 변수, PATH, 프롬프트 설정을 수집
  2. 모든 앨리어스 해제unalias -a로 기존 앨리어스를 제거하여 명령 실행의 예측 가능성 확보
  3. 사용자 함수 캡처 — 셸 함수 정의를 보존하여 빌드 도구나 커스텀 워크플로우가 정상 동작하도록 보장
  4. expand_aliases 강제 — 비인터랙티브 셸에서도 앨리어스가 확장되도록 shopt -s expand_aliases 설정
  5. rg 심(shim) 주입 — Claude Code의 Grep 도구가 내부적으로 사용하는 ripgrep 바이너리 경로를 rg 함수로 주입
주의사항

OS의 tmpdir 정리 정책(예: systemd-tmpfiles, macOS 리부트)에 의해 스냅샷이 세션 도중 삭제될 수 있습니다. 이 경우 로그인 셸(-l 플래그)로 폴백합니다. 스냅샷 기반 환경 재현이 아닌 로그인 셸 초기화를 통해 사용자 환경을 복원하므로, 약간의 동작 차이가 발생할 수 있습니다. 스냅샷이 존재하지 않으면 새로 생성하는 것이 아니라 폴백 경로를 택한다는 점에 유의하세요.

// 스냅샷 존재 여부에 따른 셸 실행 전략 (개념적 의사코드)
if (snapshotExists(sessionSnapshotPath)) {
  // 스냅샷을 source하여 환경 복원
  shellArgs = ['-c', `source ${sessionSnapshotPath}; eval '${command}'`]
} else {
  // 스냅샷 삭제 시 로그인 셸로 폴백
  shellArgs = ['-l', '-c', `eval '${command}'`]
}
04

명령 빌드 파이프라인 (6단계)

사용자(또는 모델)가 제출한 명령 문자열은 셸에 도달하기 전에 6단계 변환 파이프라인을 거칩니다. 각 단계는 특정 문제를 해결하며, 순서가 중요합니다.

단계 1 — rewriteWindowsNullRedirect()

Windows 환경에서 > NUL 패턴을 > /dev/null로 변환합니다. 모델이 Windows 학습 데이터의 영향으로 NUL 리다이렉션을 생성하는 경우를 처리하는 호환성 계층입니다.

단계 2 — shouldAddStdinRedirect()

명령에 < /dev/null을 추가할지 결정합니다. 인터랙티브 입력을 기대하는 명령(예: python, node 단독 실행)이 stdin 대기로 행(hang)되는 것을 방지합니다. 이미 파이프나 리다이렉션이 포함된 명령에는 추가하지 않습니다.

단계 3 — quoteShellCommand()

명령 전체를 작은따옴표로 래핑하여 eval에 전달합니다.

딥 다이브 — eval에 작은따옴표가 필요한 이유

스냅샷을 source한 후 명령을 실행하려면 하나의 셸 호출 안에 두 단계를 결합해야 합니다. eval '...' 패턴은 명령 문자열이 스냅샷의 source 단계에서 조기 해석되는 것을 방지합니다. 큰따옴표를 쓰면 $변수나 백틱이 source 시점에 확장되어 의도치 않은 동작이 발생합니다. 작은따옴표는 문자열을 그대로 보존한 뒤 eval 시점에 비로소 셸이 해석하도록 합니다.

단계 4 — rearrangePipeCommand()

파이프 명령의 순서를 재배치합니다.

딥 다이브 — 파이프 재배치가 필요한 이유

스냅샷 sourceeval 래핑을 사용하면 파이프의 위치가 문제가 됩니다. source snapshot.sh; eval 'cat file | grep pattern'에서 파이프 전체가 eval 내부에 있어야 정상 동작합니다. 파이프가 eval 밖에 있으면 스냅샷 환경이 파이프 우측 서브셸에 적용되지 않습니다. rearrangePipeCommand()는 파이프 구조를 분석하여 올바른 위치에 배치합니다.

단계 5 — 부품 조립

앞선 단계의 결과물을 하나의 셸 명령으로 조립합니다:

  1. source 스냅샷 파일
  2. sessionEnvScript — 세션 환경 변수 설정
  3. extglob 비활성화
  4. eval 명령 실행
  5. pwd 캡처 — 명령 실행 후 작업 디렉토리 추적
딥 다이브 — extglob 비활성화 이유

extglob(확장 글로빙)은 ?(pattern), *(pattern), +(pattern) 같은 고급 패턴 매칭을 활성화합니다. 보안 검증기가 명령을 분석한 이후extglob이 활성화되어 있으면, 검증 시점에는 무해해 보이던 패턴이 실행 시점에 임의의 경로로 확장될 수 있습니다. 검증기의 판단을 우회하는 경로 확장을 원천 차단하기 위해 shopt -u extglob으로 비활성화합니다.

단계 6 — CLAUDE_CODE_SHELL_PREFIX 적용

환경 변수 CLAUDE_CODE_SHELL_PREFIX가 설정되어 있으면 최종 명령 앞에 접두사를 추가합니다. 엔터프라이즈 환경에서 감사 로깅이나 래퍼 스크립트를 주입하는 데 사용됩니다.

// 명령 빌드 파이프라인 요약 (의사코드)
let cmd = rawCommand
cmd = rewriteWindowsNullRedirect(cmd)       // 1. NUL → /dev/null
cmd = shouldAddStdinRedirect(cmd)             // 2. < /dev/null 추가
    ? cmd + ' < /dev/null' : cmd
cmd = quoteShellCommand(cmd)                  // 3. eval용 작은따옴표 래핑
cmd = rearrangePipeCommand(cmd)               // 4. 파이프 재배치
const final = [
  `source ${snapshotPath}`,                  // 5a. 스냅샷
  sessionEnvScript,                           // 5b. 세션 환경
  'shopt -u extglob',                        // 5c. extglob 비활성화
  `eval ${cmd}`,                              // 5d. 명령 실행
  'echo "CWD=$(pwd)"',                       // 5e. pwd 캡처
].join('; ')
return shellPrefix + final                    // 6. 접두사 적용
05

21개 보안 검증기

명령이 실행되기 전에 bashCommandIsSafe() 함수가 21개의 보안 검증기를 순차적으로 실행합니다. 각 검증기는 특정 셸 인젝션 벡터나 위험 패턴을 탐지합니다. 중요한 점은 검증기가 곧바로 "실행/실패"만 결정하는 것이 아니라, 결과를 allow, ask, deny 성격의 권한 판단으로 넘긴다는 점입니다.

전체 검증기 목록

  1. INCOMPLETE_COMMANDS — 불완전한 명령(닫히지 않은 따옴표, 미완성 파이프 등) 탐지
  2. JQ_SYSTEM_FUNCTIONjq@base64d, system() 등 시스템 접근 함수 사용 탐지
  3. JQ_FILE_ARGUMENTSjq에 파일 인수를 통한 임의 파일 읽기 시도 탐지
  4. OBFUSCATED_FLAGS — 유니코드 대시나 불가시 문자로 위장된 플래그 탐지
  5. SHELL_METACHARACTERS$'\n', ANSI-C 인용 등 셸 메타문자 악용 탐지
  6. DANGEROUS_VARIABLESPROMPT_COMMAND, BASH_ENV 등 위험한 환경 변수 설정 탐지
  7. NEWLINES — 명령 내 줄바꿈을 통한 숨겨진 명령 주입 탐지
  8. DANGEROUS_PATTERNS — 세 가지 하위 범주:
    • 명령 치환 ($(), 백틱)
    • 입력 리다이렉션 (<)
    • 출력 리다이렉션 (>, >>)
  9. IFS_INJECTIONIFS 변수 조작을 통한 명령 분리 공격 탐지
  10. GIT_COMMIT_SUBSTITUTION — git 커밋 명령에서의 명령 치환 탐지. 단, 조기 허용(early allow) 경로 존재 — 안전한 커밋 패턴은 검증을 통과
  11. PROC_ENVIRON_ACCESS/proc/*/environ 접근을 통한 환경 변수 유출 시도 탐지
  12. MALFORMED_TOKEN_INJECTION — 잘못된 형식의 토큰을 통한 파서 혼동 공격 탐지
  13. BACKSLASH_ESCAPED_WHITESPACE — 백슬래시로 이스케이프된 공백을 통한 인수 결합 공격 탐지
  14. BRACE_EXPANSION{a,b,c} 중괄호 확장을 통한 다중 명령 생성 탐지
  15. CONTROL_CHARACTERS — 보이지 않는 제어 문자(0x00-0x1F 범위)를 통한 명령 은폐 탐지
  16. UNICODE_WHITESPACE — 유니코드 비표준 공백 문자(U+00A0, U+2000-U+200A 등)를 통한 시각적 위장 탐지
  17. MID_WORD_HASH — 단어 중간의 #를 통한 주석 주입 공격 탐지
  18. ZSH_DANGEROUS_COMMANDS — zsh 전용 위험 명령(zmodload, zcompile 등) 탐지
  19. BACKSLASH_ESCAPED_OPERATORS — 백슬래시로 이스케이프된 연산자(\|, \;)를 통한 파서 우회 탐지
  20. COMMENT_QUOTE_DESYNC — 주석과 따옴표의 비동기화를 이용한 코드 주입 탐지
  21. QUOTED_NEWLINE — 따옴표 안의 줄바꿈을 통한 숨겨진 명령 실행 탐지
딥 다이브 — 안전 Heredoc 조기 허용 경로

모든 줄바꿈이 위험한 것은 아닙니다. cat <<'EOF' 같은 heredoc 패턴은 멀티라인 문자열 전달의 정당한 용도입니다. 검증기는 heredoc 구조를 인식하여 안전한 패턴이면 NEWLINES 및 QUOTED_NEWLINE 검증기를 조기에 통과시킵니다. 이 조기 허용 경로가 없으면 git commit -m "$(cat <<'EOF' ...)" 같은 일반적인 패턴이 매번 권한 프롬프트를 발생시켜 사용성이 심각하게 저하됩니다.

주의사항 — 50개 서브커맨드 상한

복합 명령(파이프, &&, ||, ; 체인)을 파싱할 때 서브커맨드 수를 50개로 제한합니다. 초과 시 자동으로 ask(사용자에게 확인 요청)를 반환합니다. 이 제한은 프로덕션에서 발견된 DoS 취약점 수정입니다 — 극도로 긴 복합 명령의 보안 검증 과정에서 내부 배열이 지수적으로 성장하여 100% CPU에서 이벤트 루프가 고갈되는 현상이 발생했습니다.

06

권한 배관

명령의 실행 허용 여부는 다중 레이어 권한 검사를 통해 결정됩니다. checkPermissions()는 다음 순서로 검사를 수행합니다:

  1. checkPermissionMode() — 현재 권한 모드(plan, auto-edit 등) 확인
  2. bashCommandIsSafe() — 21개 보안 검증기 실행
  3. checkReadOnlyConstraints() — 읽기 전용 모드에서 쓰기 명령 차단
  4. checkPathConstraints() — 경로 기반 접근 제어 (허용/차단 디렉토리)
  5. checkSedConstraints()sed -i 등 인플레이스 편집 명령의 추가 제약
  6. checkCommandOperatorPermissions() — 명령 연산자(&&, ||, ;, |) 포함 명령의 권한 확인

환경 변수 스트리핑

명령 실행 전에 환경 변수를 두 단계로 필터링합니다:

주의사항

PATH, LD_PRELOAD, PYTHONPATH는 의도적으로 안전 목록에 포함되지 않습니다. 이 변수들은 실행 파일 탐색 경로, 동적 라이브러리 주입, Python 모듈 경로를 변경할 수 있어 보안 경계를 우회하는 데 악용될 수 있습니다. 필요한 경우 사용자에게 명시적 권한을 요청합니다.

규칙 매칭

사용자가 명령을 승인하면 재사용 가능한 규칙으로 저장됩니다. 세 가지 매칭 모드가 있습니다:

// 규칙 매칭 예시
// 사용자가 "git commit -m 'fix'" 실행 시 "이 세션에서 허용" 선택

// 저장되는 규칙: Bash(git commit:*) — 접두사 규칙
// 이후 git commit -m "feat: add login" → 자동 허용
// 이후 git commit --amend            → 자동 허용
// 이후 git push                       → 별도 권한 필요
07

샌드박싱

Bash 도구는 실행 환경에 따라 샌드박스를 적용합니다. shouldUseSandbox() 함수가 4방향 결정을 수행합니다:

  1. dangerouslyDisableSandbox: true — 모델이 명시적으로 요청한 경우 샌드박스 비활성화 (여전히 권한 프롬프트 필요)
  2. Docker/컨테이너 환경 — 로컬 샌드박스를 다시 씌우는 대신, 이미 제공된 격리 경계를 신뢰하는 경로가 존재
  3. 플랫폼 지원 — macOS의 sandbox-exec, Linux의 네임스페이스 격리 등 OS별 메커니즘 확인
  4. 사용자 설정 — 전역/프로젝트 설정에서 샌드박스 정책 확인

샌드박스 제약 사항

주의사항 — excludedCommands는 보안 경계가 아닙니다

샌드박스 설정의 excludedCommands는 특정 명령을 샌드박스에서 제외하는 편의 기능일 뿐, 보안 경계가 아닙니다. 사용자가 curlexcludedCommands에 추가하면 curl은 샌드박스 없이 실행되지만, 이는 네트워크 접근을 위한 편의 설정입니다. 실제 보안 제어는 권한 프롬프트가 담당합니다 — 샌드박스를 우회하더라도 위험한 명령은 여전히 사용자 승인이 필요합니다.

08

백그라운드 실행

Bash 도구는 세 가지 경로로 백그라운드 실행을 지원합니다:

  1. run_in_background: true (모델) — 모델이 명시적으로 백그라운드 실행을 요청. 오래 걸리는 빌드, 테스트, 서버 시작 등에 사용. 즉시 backgroundTaskId를 반환하고 완료 시 알림
  2. Ctrl+B (사용자) — 실행 중인 명령을 사용자가 수동으로 백그라운드로 전환. 대화를 계속하면서 결과를 나중에 확인 가능
  3. 15초 후 자동 (어시스턴트 모드) — 어시스턴트 턴 중 명령이 15초 이상 실행되면 자동으로 백그라운드로 전환. 긴 빌드가 대화 흐름을 차단하지 않도록 보장

Sleep 차단기

독립적인 sleep N 명령(N ≥ 2)은 Monitor 도구가 활성 상태일 때 자동으로 차단됩니다. 모델이 폴링 루프에서 sleep 5를 반복 호출하는 비효율적 패턴을 방지하기 위함입니다. Monitor 도구가 이미 주기적 확인을 수행하고 있으므로 별도의 sleep은 불필요합니다.

// 백그라운드 실행 3가지 트리거
// 1. 모델 요청
{ command: "npm run build", run_in_background: true }
// → 즉시 반환: { backgroundTaskId: "task-abc123" }

// 2. 사용자 수동 전환: 실행 중 Ctrl+B

// 3. 자동 전환: 어시스턴트 모드에서 15초 초과 시
// → 자동 백그라운드 전환 + 완료 시 알림
09

출력 처리

명령 실행 결과는 여러 단계의 처리를 거쳐 모델에게 전달됩니다.

출력 크기 제한

출력이 제한을 초과하면 중간 부분을 잘라내고 시작과 끝 부분을 보존합니다. 오류 메시지는 주로 출력 끝에 위치하므로 이 전략이 디버깅에 유용합니다.

이미지 감지

출력에 base64 인코딩된 PNG 또는 JPEG 데이터가 감지되면 텍스트 대신 이미지로 처리하여 멀티모달 모델에게 시각적 콘텐츠로 전달합니다.

의미적 종료 코드 해석

종료 코드를 단순한 성공/실패가 아닌 명령의 의미에 맞게 해석합니다:

이를 통해 모델이 정상적인 비-매칭 결과를 오류로 오판하는 것을 방지합니다.

Claude Code Hints 프로토콜

명령 출력에 <claude-code-hint /> 태그가 포함되어 있으면, 이 태그는 모델에게 전달되기 전에 제거됩니다. 이 프로토콜은 도구나 스크립트가 Claude Code 시스템에 메타데이터를 전달하되, 모델의 컨텍스트 윈도우를 오염시키지 않도록 설계되었습니다.

// 출력 처리 파이프라인 (개념적)
let output = rawOutput                         // 원시 출력

// 1. 크기 제한 적용
if (output.length > 150_000) {
  output = truncateMiddle(output, 150_000)     // 하드 캡
}

// 2. 이미지 감지
if (containsBase64Image(output)) {
  return { type: 'image', data: extractImage(output) }
}

// 3. 의미적 종료 코드 해석
const exitCodeMeaning = interpretExitCode(command, exitCode)

// 4. Hints 태그 제거
output = output.replace(/<claude-code-hint \/>/g, '')
10

UI 분류

UI 분류

Bash 명령은 UI 표시를 위해 여러 카테고리로 분류됩니다: BASH_SEARCH_COMMANDS, BASH_READ_COMMANDS, BASH_LIST_COMMANDS, BASH_SEMANTIC_NEUTRAL_COMMANDS. 파이프라인 규칙: 파이프라인의 모든 부분이 검색/읽기여야 전체 파이프라인이 축소 가능합니다. Sed의 인플레이스 편집은 파일 편집 작업으로 렌더됩니다.

11

핵심 요약

핵심 포인트

  • 셸 스냅샷은 세션당 한 번 생성되어 사용자의 셸 환경을 재현합니다. 삭제되면 로그인 셸(-l 플래그)로 폴백합니다
  • 명령 빌드 파이프라인은 6단계를 거칩니다: Windows 호환 → stdin 리다이렉트 → 작은따옴표 래핑 → 파이프 재배치 → 부품 조립 → 접두사 적용
  • extglob은 보안 검증 후 경로 확장을 방지하기 위해 의도적으로 비활성화됩니다
  • 21개 보안 검증기가 셸 인젝션, 유니코드 위장, 제어 문자, IFS 조작 등 다양한 공격 벡터를 탐지합니다
  • 50개 서브커맨드 상한은 프로덕션 DoS 취약점(지수적 배열 성장으로 인한 CPU 고갈)을 수정한 것입니다
  • 환경 변수 스트리핑에서 PATH, LD_PRELOAD, PYTHONPATH는 의도적으로 안전 목록에 미포함됩니다 — 보안 경계 우회 방지
  • excludedCommands는 편의 기능이지 보안 경계가 아닙니다 — 실제 보안 제어는 권한 프롬프트가 담당합니다
  • 확장 입력 스키마는 공개 입력 위에 제어 필드를 더합니다. run_in_background는 공개 실행 제어에 쓰일 수 있고, dangerouslyDisableSandbox는 내부 경로 성격이 더 강합니다
  • 결과 표면에는 stdoutstderr가 모두 있지만, 기본 실행 경로에서는 2>&1 병합 때문에 실제 오류 메시지를 stdout에서 읽는 경우가 많습니다
  • 출력은 하드 캡 150,000자, 기본 30,000자로 제한됩니다. 중간 부분을 잘라내고 시작/끝을 보존합니다
  • 백그라운드 실행은 모델 요청, 사용자 Ctrl+B, 15초 자동 전환의 세 가지 경로로 트리거됩니다
12

지식 확인

퀴즈 — 5문제

Q1. 사용자가 권한 프롬프트에서 git commit -m "fix"를 승인할 때 저장되는 규칙은?

  • A) 정확한 일치 — git commit -m "fix"만 자동 허용
  • B) Bash(git commit:*) — 접두사 규칙으로 모든 git commit 변형 허용
  • C) 모든 git 명령 자동 허용
  • D) 모든 bash 명령 자동 허용
권한 승인 시 접두사 규칙 Bash(git commit:*)이 저장됩니다. 이후 git commit -m "feat: ...", git commit --amendgit commit으로 시작하는 모든 변형이 자동 허용되지만, git pushgit reset 같은 다른 git 명령에는 별도 권한이 필요합니다.

Q2. OS tmpdir 정리로 셸 스냅샷이 세션 중 삭제되면 어떻게 되나요?

  • A) 명령 실행이 실패하고 오류 반환
  • B) 새 스냅샷을 즉시 생성
  • C) 로그인 셸(-l 플래그)로 폴백하여 사용자 환경 복원
  • D) 세션이 자동 종료
스냅샷이 삭제되면 새로 생성하는 것이 아니라 로그인 셸(-l 플래그)로 폴백합니다. 로그인 셸은 .bash_profile, .zprofile 등을 읽어 사용자 환경을 복원하지만, 스냅샷 방식과 약간의 동작 차이가 있을 수 있습니다.

Q3. echo $'\n'evil_command를 잡는 검증기는?

  • A) NEWLINES (#7) — 줄바꿈 탐지
  • B) SHELL_METACHARACTERS (#5) — 셸 메타문자 탐지
  • C) DANGEROUS_PATTERNS — 명령 치환 (#8)과 ANSI-C 인용
  • D) CONTROL_CHARACTERS (#17) — 제어 문자 탐지
$'\n'은 ANSI-C 인용 구문으로, 셸 메타문자의 한 형태입니다. SHELL_METACHARACTERS (#5) 검증기가 이 패턴을 탐지합니다. NEWLINES 검증기는 리터럴 줄바꿈을 탐지하고, CONTROL_CHARACTERS는 직접적인 제어 문자 바이트를 탐지하지만, ANSI-C 인용은 셸 메타문자 범주에 해당합니다.

Q4. Bash 도구 출력의 stderr 필드가 거의 항상 비어있는 이유는?

  • A) 오류가 자동으로 억제되기 때문
  • B) 셸 프로바이더가 2>&1로 병합하여 두 스트림 모두 stdout에 기록되기 때문
  • C) 오류가 예외(exception)로 처리되기 때문
  • D) Zod 스키마에서 선택적(optional) 필드이기 때문
셸 프로바이더가 명령 실행 시 2>&1 리다이렉션을 적용하여 stderr를 stdout으로 병합합니다. 따라서 오류 메시지를 포함한 모든 출력이 stdout 필드에 기록되고, stderr 필드는 빈 문자열로 남습니다. 오류가 억제되는 것이 아니라 같은 스트림에 합쳐지는 것입니다.

Q5. 복합 명령을 50개 서브커맨드로 제한하고 초과 시 ask를 반환하는 이유는?

  • A) 파일시스템 과부하를 방지하기 위해
  • B) Zod 스키마가 최대 50개만 지원하기 때문
  • C) 프로덕션 DoS 수정 — 지수적 배열 성장이 100% CPU에서 이벤트 루프를 고갈시켰기 때문
  • D) Bash 자체의 명령 체인 제한
프로덕션에서 발견된 DoS 취약점의 수정입니다. 극도로 긴 복합 명령의 보안 검증 과정에서 내부 배열이 지수적으로 성장하여 100% CPU 사용률에서 Node.js 이벤트 루프가 고갈되는 현상이 발생했습니다. 50개 상한은 이 CPU 고갈 공격을 방지하면서도 실용적인 복합 명령을 허용하는 균형점입니다.
0 / 5