# 보안

환경 변수 관리와 파일 시스템 접근 권한 제한 등 안전한 에이전트 실행 환경을 다룹니다.

원본 URL: https://abc.noco.kr/harness-basics/security

에이전트에게 지시하는 문장과 실제로 실행되는 환경은 다른 층위다. 룰에 "하지 마라"고 적어도 셸 명령은 그대로 실행된다. 막으려면 [환경 변수](/harness-basics/settings)로 값을 감추고, 권한 규칙과 샌드박스로 접근 범위를 좁혀야 한다.

기준일: 2026-09-30

## 비밀값은 환경 변수로

키와 토큰은 요청문에 붙여 넣지 않는다. 요청문은 대화 기록에 남고, 여러 사람이 나누는 로그에도 남을 수 있다.

```text
요청문:  "GITHUB_TOKEN으로 저장소를 확인해 줘"
설정:    GITHUB_TOKEN은 실행 환경에서만 읽히게 둔다
```

로컬에서는 `.env` 파일에 두고, 커밋 대상에서 제외한다. 제외 대상은 저장소 설정 파일에 남겨 두면 새 폴더를 만들 때 빠지지 않는다.

```gitignore
.env
.env.*
!.env.example
```

실제 값을 넣지 않는 예시 파일을 하나 함께 둔다. 필요한 키 이름과 설명만 적어 두면 다른 사람은 값을 채워 넣을 수 있다.

```text
# .env.example
GITHUB_TOKEN=            # GitHub 저장소 읽기·코멘트에 사용
NOTION_API_KEY=          # Notion MCP 연결에 사용
```

값을 문서나 예시 파일에 옮기면 그대로 노출된다. 예시 파일에는 키 이름과 용도만 남긴다. 저장소에 이미 올라간 값은 이력 전체에서 지우기 어려우므로 처음부터 넣지 않는 편이 빠르다.

## 권한 규칙과 샌드박스의 역할

[룰](/glossary#rules)의 문장은 모델이 읽는 지시다. 권한 규칙과 샌드박스는 런타임이 실제로 막는 장치다. 둘 다 있어야 범위가 유지된다.

| 층위 | 막는 대상 | 남는 한계 |
|---|---|---|
| 룰·지시문 | 모델이 시도하지 않게 유도 | 강제하지 못한다 |
| 권한 규칙 | 특정 파일·명령에 대한 허용과 거부 | 규칙에 없는 경로는 기본값을 따른다 |
| 샌드박스 | 셸과 자식 프로세스의 실제 접근 | 설정한 범위 안에서의 실수는 막지 못한다 |

[Claude Code](/glossary#claude-code)는 권한 규칙을 거부 → 확인 → 허용 순서로 평가하고, `/sandbox`로 셸과 자식 프로세스의 파일·네트워크 접근을 제한한다. 비밀 파일에 읽기 거부를 걸어도 셸을 통한 접근은 별도로 막아야 한다.

[Codex](/glossary#codex)의 로컬 실행 환경은 운영체제 샌드박스에서 네트워크를 기본 차단하고 쓰기를 작업 공간으로 제한한다. 승인을 전혀 묻지 않는 모드로 바꿔도 샌드박스 설정 자체가 바뀌지는 않는다. 무승인은 승인 절차만 없애는 선택지이고, 격리를 없애는 선택지가 아니다.

## 파괴 명령과 외부 접근

가장 많이 발생하는 사고는 지시문이 아니라 명령이다. 다음은 기본적으로 막아 둘 대상이다.

```text
rm        삭제
mv        옮기기
chmod     권한 변경
작업 공간 밖 쓰기    다른 폴더·홈 디렉터리·시스템 경로
force 옵션      되돌리기 어려운 변경
```

권한 규칙은 런타임마다 문법이 다르다. 다음은 개념을 보여 주는 의사 설정이다. 실제 설정에 복사하지 말고, 사용하는 런타임의 공식 문법과 규칙 형식을 확인한다.

```json
{
  "permissions": {
    "deny": [
      "Read(./.env)",
      "Edit(./secrets/**)",
      "Bash(rm -rf:*)"
    ],
    "ask": [
      "Bash(git push:*)",
      "Bash(gh pr:*)"
    ]
  }
}
```

규칙을 좁힐 때는 경로와 명령을 함께 적는다. `rm`만 막으면 옵션이 붙은 호출을 통과할 수 있고, `Bash(rm:*)`처럼 접두사만 보면 다른 명령어의 일부와 겹칠 수 있다. 규칙이 실제로 막는지는 작은 연습 저장소에서 한 번 실행해 확인한다.

막았다고 생각한 경로가 셸로는 열려 있을 수 있다. 읽기 거부를 걸어 둔 파일이 `cat`으로 읽히면 규칙은 읽기 도구에만 동작한 것이다. 이 경우 샌드박스에서 해당 경로가 격리돼 있는지 확인한다.

## 자동 승인의 범위 제한

[Claude Code](/glossary#claude-code)와 [Codex](/glossary#codex) 모두 자동 승인이나 자동 허용 설정을 제공한다. 승인 대기를 없애면 속도는 붙지만, 한 번의 실수가 그대로 실행된다.

| 자동 허용해도 되는 것 | 확인을 남길 것 |
|---|---|
| 저장소 안 파일 읽기 | 파일 삭제·이동 |
| 빌드·테스트·린트 실행 | 패키지 설치와 버전 변경 |
| 포맷과 자동 수정 | 커밋과 푸시 |
| 검색과 파일 목록 보기 | 외부 요청과 메시지 전송 |

넓게 허용하기보다 자주 쓰는 명령부터 하나씩 추가한다. 자동 승인을 켠 상태로 처음 하는 작업은 연습 저장소에서 먼저 확인한다.

승인 절차를 없앴다면 대신 기록을 남긴다. 무엇을 허용했는지 설정 파일에 적어 두고, 나중에 범위를 좁힐 때 기준이 되게 한다. 허용 범위는 시간이 지나면 실제 필요보다 넓어지기 쉬우므로 [문서](/harness-basics/docs)에 남겨 둔다.

## 확인 순서

보안 설정은 한 번 하고 끝나지 않는다. 다음 순서로 점검하면 변경이 빠르다.

| 순서 | 확인할 것 | 흔한 문제 |
|---|---|---|
| 1 | 비밀값 위치 | 요청문·문서에 값이 남아 있다 |
| 2 | 커밋 제외 목록 | `.env`가 추적 대상이다 |
| 3 | 샌드박스 여부 | 꺼져 있거나 작업 공간 밖으로 넓다 |
| 4 | 권한 규칙 | 금지한 명령이 다른 형태로 통과한다 |
| 5 | 자동 승인 범위 | 필요한 것보다 넓게 열려 있다 |
| 6 | 기록 | 무엇을 했는지 남지 않는다 |

로그와 알림에 붙는 내용도 확인한다. 작업 요약에는 변경 파일과 검증 결과만 두고, 환경 변수의 값과 전체 로그 본문은 옮기지 않는다. [훅](/harness-advanced/hooks)으로 알림을 보낼 때 특히 빈번하다.

::: details 보충: 보안 점검 체크리스트와 공식 문서
[Claude Code 권한 안내](https://code.claude.com/docs/en/permissions)는 권한 규칙이 거부 → 확인 → 허용 순서로 평가한다고 설명하고, 비밀 파일에 읽기 거부를 둘 수 있다고 밝힌다. 다만 셸 접근은 별도로 통제해야 한다. [샌드박스 안내](https://code.claude.com/docs/en/sandboxing)는 `/sandbox`로 셸과 자식 프로세스의 파일·네트워크 접근을 제한하는 절차를 담고 있다. 권한 우회 모드는 격리된 환경에서만 쓰라고 명시한다.

[Codex의 승인·보안 안내](https://learn.chatgpt.com/docs/agent-approvals-security)는 로컬 CLI와 IDE가 운영체제 샌드박스에서 네트워크를 기본 차단하고 쓰기를 작업 공간으로 제한한다고 설명한다. 승인을 묻지 않는 모드로 실행해도 이 기본 제약은 유지된다. [Codex 메모리 안내](https://learn.chatgpt.com/docs/customization/memories)는 메모리와 공유 상태 파일에 비밀값이 들어가지 않도록 검토하라고 권한다.

점검할 항목을 한 장으로 모으면 다음과 같다. 비밀값이 요청문·문서·로그에 없는가, 비밀 파일이 커밋 대상이 아닌가, 삭제·이동 명령이 막혀 있는가, 작업 공간 밖 쓰기가 제한되는가, 자동 승인이 필요한 것까지 포함하지 않았는가, 허용 범위가 문서에 남아 있는가. 허용을 넓히는 변경은 배포 정책이나 보안 정책과 같은 수준으로 사람이 확인한다. 기준일: 2026-09-30.
:::
