haechi 1.1.1 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ko.md +97 -97
- package/README.md +2 -2
- package/SECURITY.md +12 -10
- package/docs/current/api-stability.ko.md +26 -26
- package/docs/current/configuration.ko.md +101 -101
- package/docs/current/configuration.md +4 -4
- package/docs/current/release-process.ko.md +19 -20
- package/docs/current/release-process.md +1 -2
- package/docs/current/reliability-hardening-track.ko.md +77 -0
- package/docs/current/reliability-hardening-track.md +77 -0
- package/docs/current/risk-register-release-gate.ko.md +25 -27
- package/docs/current/risk-register-release-gate.md +18 -20
- package/docs/current/shared-responsibility.ko.md +33 -24
- package/docs/current/shared-responsibility.md +12 -3
- package/docs/current/threat-model.ko.md +10 -11
- package/docs/current/threat-model.md +1 -2
- package/package.json +2 -1
- package/packages/cli/runtime.mjs +8 -1
- package/packages/core/index.mjs +47 -8
- package/packages/proxy/index.mjs +17 -2
package/README.ko.md
CHANGED
|
@@ -12,23 +12,23 @@
|
|
|
12
12
|
|
|
13
13
|
[English](README.md) | **한국어**
|
|
14
14
|
|
|
15
|
-
Haechi는 LLM
|
|
15
|
+
Haechi는 LLM·MCP·vLLM·Ollama 및 에이전트 payload가 모델, 도구, 로그, proxy에 도달하기 전에 보호하는 자체 호스팅 AI 컨텍스트 집행 레이어입니다.
|
|
16
16
|
|
|
17
|
-
이름은
|
|
17
|
+
이름은 분별과 보호를 상징하는 한국의 수호 신수 해치에서 따왔습니다.
|
|
18
18
|
|
|
19
|
-
이 저장소는 로컬 개발, 보안 설계 검토, 자체 호스팅 통합 실험을 위한
|
|
19
|
+
이 저장소는 로컬 개발, 보안 설계 검토, 자체 호스팅 통합 실험을 위한 것입니다. 컴플라이언스를 보장하지는 않습니다.
|
|
20
20
|
|
|
21
|
-
**1.0.0이 첫 stable
|
|
21
|
+
**1.0.0이 첫 stable 릴리스입니다.** 1.0부터 public API는 strict semver 하의 frozen 계약입니다. `package.json`의 `exports` 표면, CLI의 기계 판독 동작, audit event schema, config key shape이 모두 major 버전 계약의 일부이며, 문서화된 deprecation 정책과 in-minor 보안 예외 하나가 함께 적용됩니다. [`docs/current/api-stability.md`](docs/current/api-stability.md)를 참고하세요. 네 개의 `haechi-*` 위성은 pre-1.0으로 유지되며 core와 독립적으로 버저닝됩니다.
|
|
22
22
|
|
|
23
|
-
현재 범위는 로컬 도입에 초점을
|
|
23
|
+
현재 범위는 로컬 도입에 초점을 맞춥니다.
|
|
24
24
|
|
|
25
|
-
- `haechi init`: 로컬 키, 샘플 설정, audit 경로를
|
|
26
|
-
- `haechi protect`: OpenAI 호환 JSON payload를 검사하고
|
|
27
|
-
- `haechi report`: 원시 payload 없이 audit 이벤트를
|
|
28
|
-
- `haechi proxy`: 기존 LLM
|
|
29
|
-
- `haechi status`: 현재
|
|
30
|
-
- `haechi audit-verify`: audit hash chain을 검증하고 head hash를
|
|
31
|
-
- `haechi mcp-wrap -- <command>`: MCP 서버를 양방향 stdio 보호로
|
|
25
|
+
- `haechi init`: 로컬 키, 샘플 설정, audit 경로를 생성합니다
|
|
26
|
+
- `haechi protect`: OpenAI 호환 JSON payload를 검사하고 보호합니다
|
|
27
|
+
- `haechi report`: 원시 payload 없이 audit 이벤트를 요약합니다
|
|
28
|
+
- `haechi proxy`: 기존 LLM 호출 앞에 두는 로컬 HTTP JSON proxy를 실행합니다
|
|
29
|
+
- `haechi status`: 현재 설정에서 무엇이 보호되고 무엇이 보호되지 않는지 보여 줍니다
|
|
30
|
+
- `haechi audit-verify`: audit hash chain을 검증하고 head hash를 출력합니다
|
|
31
|
+
- `haechi mcp-wrap -- <command>`: MCP 서버를 양방향 stdio 보호로 감쌉니다
|
|
32
32
|
|
|
33
33
|
## 설치
|
|
34
34
|
|
|
@@ -45,7 +45,7 @@ npx haechi init
|
|
|
45
45
|
|
|
46
46
|
## 빠른 시작
|
|
47
47
|
|
|
48
|
-
이 저장소를 클론한
|
|
48
|
+
이 저장소를 클론한 뒤:
|
|
49
49
|
|
|
50
50
|
```bash
|
|
51
51
|
npm test
|
|
@@ -54,9 +54,9 @@ npm run demo:protect
|
|
|
54
54
|
npm run demo:report
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
-
기본 설정은 `dry-run` 모드로
|
|
57
|
+
기본 설정은 `dry-run` 모드로 실행됩니다. 민감한 값을 탐지하고 audit 메타데이터를 기록하지만, 정책 모드를 바꾸기 전까지는 아웃바운드 payload를 수정하지 않습니다.
|
|
58
58
|
|
|
59
|
-
`npm run demo:init`은 `haechi.config.json`과 `.haechi/dev.keys.json`을 로컬에
|
|
59
|
+
`npm run demo:init`은 `haechi.config.json`과 `.haechi/dev.keys.json`을 로컬에 생성합니다. 생성된 키 파일은 로컬 개발 전용입니다. 코어 자체에는 운영용 KMS/HSM/Vault 키 provider가 없으며, KMS·Vault 기반 키 custody는 `haechi-crypto-kms` 위성이 외부 `cryptoProvider` 계약을 통해 제공합니다. 비밀 값이 없는 템플릿은 `haechi.config.example.json`에서 확인할 수 있습니다.
|
|
60
60
|
|
|
61
61
|
## Local Proxy
|
|
62
62
|
|
|
@@ -64,19 +64,19 @@ npm run demo:report
|
|
|
64
64
|
node packages/cli/bin/haechi.mjs proxy --config haechi.config.json
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
-
기존 HTTP JSON 클라이언트를 `http://localhost:11016`으로
|
|
67
|
+
기존 HTTP JSON 클라이언트를 `http://localhost:11016`으로 향하게 하고, `haechi.config.json`에서 `target.upstream`을 설정합니다. 다른 로컬 포트를 쓰려면 설정의 `proxy.port`를 바꾸거나 `--port`를 전달하세요.
|
|
68
68
|
|
|
69
|
-
proxy는 기본적으로 loopback에
|
|
69
|
+
proxy는 기본적으로 loopback에 바인딩됩니다. `0.0.0.0`, `::`, 또는 그 밖의 non-loopback 호스트에 바인딩하려면 `--allow-remote-bind`를 명시적으로 전달해야 합니다. 이 플래그는 명시적인 네트워크 접근 통제가 있을 때만 사용하세요.
|
|
70
70
|
|
|
71
|
-
`stream: true`인 스트리밍 요청은 기본적으로
|
|
71
|
+
`stream: true`인 스트리밍 요청은 기본적으로 차단됩니다. `streaming.requestMode`를 `inspect`로 설정하면 SSE/NDJSON 응답을 stream-filter합니다(bounded sliding buffer가 프레임에 걸쳐 나뉜 PII도 잡아냅니다. `streaming.maxMatchBytes` 참고). 호출자가 보호되지 않는 스트리밍을 명시적으로 감수하는 경우에만 `pass-through`로 설정하세요.
|
|
72
72
|
|
|
73
|
-
Ollama의 `/api/chat`과 `/api/generate`는 `stream` 필드가
|
|
73
|
+
Ollama의 `/api/chat`과 `/api/generate`는 `stream` 필드가 없으면 기본적으로 스트리밍하므로, proxy는 `stream: false`가 명시되지 않는 한 이 요청들을 스트리밍으로 간주합니다.
|
|
74
74
|
|
|
75
|
-
upstream 요청은 `limits.upstreamTimeoutMs`(기본값 120000) 이후 타임아웃되며 `504 haechi_upstream_timeout`으로
|
|
75
|
+
upstream 요청은 `limits.upstreamTimeoutMs`(기본값 120000) 이후 타임아웃되며 `504 haechi_upstream_timeout`으로 실패합니다.
|
|
76
76
|
|
|
77
77
|
## Local Inference Servers
|
|
78
78
|
|
|
79
|
-
Haechi는 OpenAI 호환 서버, vLLM, Ollama, llama.cpp
|
|
79
|
+
Haechi는 OpenAI 호환 서버, vLLM, Ollama, llama.cpp용 프로토콜 adapter 프리셋을 제공합니다.
|
|
80
80
|
|
|
81
81
|
```json
|
|
82
82
|
{
|
|
@@ -96,11 +96,11 @@ Haechi는 OpenAI 호환 서버, vLLM, Ollama, llama.cpp를 위한 프로토콜 a
|
|
|
96
96
|
}
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
-
그런 다음 OpenAI 호환 클라이언트를 `http://127.0.0.1:11016/v1`으로
|
|
99
|
+
그런 다음 OpenAI 호환 클라이언트를 `http://127.0.0.1:11016/v1`으로 향하게 합니다. Ollama 네이티브 API는 `target.adapter: "ollama"`를 사용하고 proxy를 통해 `/api/chat` 또는 `/api/generate`를 호출하세요.
|
|
100
100
|
|
|
101
101
|
## 토큰 왕복
|
|
102
102
|
|
|
103
|
-
tokenization을
|
|
103
|
+
tokenization을 쓰면 모델은 안정적인 token을 받고 호출자는 평문을 돌려받습니다.
|
|
104
104
|
|
|
105
105
|
```json
|
|
106
106
|
{
|
|
@@ -113,12 +113,12 @@ tokenization을 사용하면 모델은 안정적인 token을 받고 호출자는
|
|
|
113
113
|
}
|
|
114
114
|
```
|
|
115
115
|
|
|
116
|
-
- `tokenVault.deterministic`
|
|
117
|
-
- `tokenVault.detokenizeResponses`
|
|
116
|
+
- `tokenVault.deterministic`(기본값 `false`): 같은 값이 항상 같은 token으로 매핑됩니다(로컬 키에서 파생한 도메인 분리 키로 HMAC하며, 원시 AES 키는 쓰지 않습니다). 다시 전송된 대화 기록이 같은 token으로 재tokenize되므로 멀티턴 채팅에 필요합니다. **트레이드오프:** 같은 값을 요청 간에 연결할 수 있게 됩니다. `deterministicTypes`(예: `["email"]`)로 determinism을 선택한 type으로만 제한할 수 있습니다.
|
|
117
|
+
- `tokenVault.detokenizeResponses`(기본값 `false`): 같은 요청을 보호하는 동안 발급된 token**만** 그 요청의 응답에서 복원합니다. 다른 클라이언트나 요청의 token은 복원하지 않습니다. `revealPolicy`와는 독립적이며, 모든 복원은 개수만 audit에 기록하고 값은 기록하지 않습니다. `responseProtection.enabled`가 필요합니다.
|
|
118
118
|
|
|
119
119
|
## MCP Wrap
|
|
120
120
|
|
|
121
|
-
stdio MCP 서버를
|
|
121
|
+
stdio MCP 서버를 감싸 양방향 트래픽을 필터링합니다. MCP 클라이언트 설정에서 커맨드만 바꾸면 됩니다.
|
|
122
122
|
|
|
123
123
|
```json
|
|
124
124
|
{
|
|
@@ -131,25 +131,25 @@ stdio MCP 서버를 래핑하여 양방향 트래픽을 필터링한다 — MCP
|
|
|
131
131
|
}
|
|
132
132
|
```
|
|
133
133
|
|
|
134
|
-
클라이언트→서버 요청은 `mcp.allowedMethods` allowlist와 params 보호를
|
|
134
|
+
클라이언트→서버 요청은 `mcp.allowedMethods` allowlist와 params 보호를 거치고, 서버→클라이언트 결과는 params/result 보호와 injection 휴리스틱(아래 참고)을 적용받습니다. 거부된 요청은 클라이언트에 응답되고 서버에는 도달하지 않습니다. stderr과 exit code는 그대로 전달됩니다.
|
|
135
135
|
|
|
136
136
|
## Injection Detection (Preview)
|
|
137
137
|
|
|
138
|
-
|
|
138
|
+
응답과 tool result 텍스트는 간접 prompt injection(지시문 재정의, 역할 재할당, prompt 마커, 사용자에게 숨기기, 은밀한 tool 유도)을 찾는 휴리스틱 규칙으로 검사됩니다. `injection` type은 **기본적으로 report-only**입니다. 탐지 결과는 audit 로그에 기록하지만 수정하거나 차단하지는 않습니다. 신호를 신뢰할 수 있다고 판단되면 명시적으로 격상하세요.
|
|
139
139
|
|
|
140
140
|
```json
|
|
141
141
|
{ "policy": { "actions": { "injection": "block" } } }
|
|
142
142
|
```
|
|
143
143
|
|
|
144
|
-
이 휴리스틱은 prompt injection
|
|
144
|
+
이 휴리스틱은 prompt injection을 완전히 막아 주지는 않습니다. `docs/current/threat-model.md`를 참고하세요.
|
|
145
145
|
|
|
146
146
|
## 인증 및 클라이언트별 통제
|
|
147
147
|
|
|
148
|
-
하나의 host 앞에 여러 클라이언트/에이전트를 두는 경우, bearer auth를
|
|
148
|
+
하나의 host 앞에 여러 클라이언트/에이전트를 두는 경우, bearer auth를 켜고 각 클라이언트를 policy profile에 바인딩합니다. Token은 별도의 `.haechi/auth.json`(0600)에 keyed-HMAC 해시로만 저장됩니다.
|
|
149
149
|
|
|
150
150
|
```bash
|
|
151
151
|
haechi auth add --type service --scope team:eng --label env=prod # 토큰을 한 번만 출력
|
|
152
|
-
haechi auth list #
|
|
152
|
+
haechi auth list # 토큰은 표시하지 않음
|
|
153
153
|
haechi auth revoke <id>
|
|
154
154
|
```
|
|
155
155
|
|
|
@@ -167,53 +167,53 @@ haechi auth revoke <id>
|
|
|
167
167
|
}
|
|
168
168
|
```
|
|
169
169
|
|
|
170
|
-
- **Bearer auth**
|
|
171
|
-
- **Named profiles**: 인증된 identity는 **scope → label → 필수 `default`** 순으로 profile
|
|
170
|
+
- **Bearer auth**(`auth.provider: bearer`): 클라이언트가 `Authorization: Bearer <token>`을 보냅니다. 없거나 잘못되었거나 revoke된 경우 → `401`(바디를 읽지 않고 upstream에도 도달하지 않습니다). `provider: none`(기본값)은 동작을 그대로 두며, `external`은 주입된 `authProvider`가 필요합니다.
|
|
171
|
+
- **Named profiles**: 인증된 identity는 **scope → label → 필수 `default`** 순으로 profile에 매핑됩니다(매칭이 없거나 익명이면 `default`로 fail-closed). Profile은 기본 policy를 덮어쓰며 자체 `modelAllowlist`와 `rate`를 가질 수 있습니다.
|
|
172
172
|
- **Model allowlist**: 허용되지 않은 `model`을 가진 요청 → `403`.
|
|
173
|
-
- **Rate limit**: identity별 분당 요청 수 → `429`
|
|
174
|
-
- Audit
|
|
173
|
+
- **Rate limit**: identity별 분당 요청 수 → `429`(인메모리, 프로세스별).
|
|
174
|
+
- Audit 이벤트에는 **PII-safe** `identity`(keyed-HMAC subject/issuer이며 원시 값이 아닙니다)와 매핑된 `profile`이 들어가고, `auth_denied`/`model_not_allowed`/`rate_limited` 결정에는 credential이 포함되지 않습니다. `/__haechi/health`는 인증 없이 접근할 수 있습니다.
|
|
175
175
|
|
|
176
|
-
JWT/JWKS 인증과 KMS 기반 key custody는 `haechi-*` 위성 패키지로 제공되며, 각각 core와 독립적으로
|
|
176
|
+
JWT/JWKS 인증과 KMS 기반 key custody는 `haechi-*` 위성 패키지로 제공되며, 각각 core와 독립적으로 버저닝·발행됩니다. 위성은 pre-1.0으로 유지되며 `haechi` peer 범위를 `>=0.8.0 <2.0.0`으로 선언합니다(상한이 core major를 따라가므로 core 1.0.0이 위성 설치를 깨뜨리지 않습니다).
|
|
177
177
|
|
|
178
|
-
- [`haechi-auth-jwt`](satellites/auth-jwt/)
|
|
179
|
-
- [`haechi-crypto-kms`](satellites/crypto-kms/)
|
|
180
|
-
- [`haechi-dashboard`](satellites/dashboard/)
|
|
181
|
-
- [`haechi-auth-oidc`](satellites/auth-oidc/)
|
|
178
|
+
- [`haechi-auth-jwt`](satellites/auth-jwt/)(0.2.1) — 헤드리스 JWKS bearer 검증. 재사용 가능한 JWS 검증기(`createJwtVerifier`)를 추가로 export합니다.
|
|
179
|
+
- [`haechi-crypto-kms`](satellites/crypto-kms/)(0.2.1) — 실제 KMS 클라이언트 기반 envelope 암호화. AWS에 더해 GCP(`./gcp`), Azure(`./azure`), HashiCorp Vault Transit(`./vault`, `node:` 전용) 백엔드를 지원합니다.
|
|
180
|
+
- [`haechi-dashboard`](satellites/dashboard/)(0.1.2) — audit 로그와 hash chain 상태를 보는 zero-dependency 읽기 전용 audit 뷰어(`node:http`)입니다.
|
|
181
|
+
- [`haechi-auth-oidc`](satellites/auth-oidc/)(0.1.2) — 대시보드의 사람 로그인을 담당하는 대화형 OIDC 세션 브로커(authorization-code + PKCE)입니다.
|
|
182
182
|
|
|
183
|
-
|
|
183
|
+
위성은 기본적으로 `node:` 전용이며(무거운 SDK는 optional peer), core를 zero-dependency로 유지합니다.
|
|
184
184
|
|
|
185
185
|
## 설정
|
|
186
186
|
|
|
187
|
-
`haechi init`은 `haechi.config.json`을 생성하며, 비밀
|
|
187
|
+
`haechi init`은 `haechi.config.json`을 생성하며, 비밀 값이 없는 템플릿은 `haechi.config.example.json`에 있습니다. 모든 키는 fail-closed로 검증되어, 알 수 없거나 형식이 잘못된 값은 시작을 거부합니다.
|
|
188
188
|
|
|
189
189
|
| 키 | 기본값 | 설명 |
|
|
190
190
|
|---|---|---|
|
|
191
|
-
| `mode` / `policy.mode` | `dry-run` | `dry-run`과 `report-only`는
|
|
192
|
-
| `target.type` / `target.adapter` | `llm-http` / `openai-compatible` | upstream 프로토콜: `openai-compatible`, `vllm-openai`, `ollama`, `llama-cpp`. 알 수 없는 type은 fail-closed로
|
|
193
|
-
| `target.upstream` | `http://127.0.0.1:9999` | proxy가 요청을 전달하는 유일한 upstream
|
|
194
|
-
| `proxy.host` / `proxy.port` | `127.0.0.1` / `11016` | proxy 바인드 주소.
|
|
195
|
-
| `responseProtection.enabled` | `false` | upstream JSON 응답을
|
|
196
|
-
| `responseProtection.maxBytes` | `1048576` | 응답
|
|
197
|
-
| `streaming.requestMode` | `block` | `block`은 스트리밍을 501
|
|
191
|
+
| `mode` / `policy.mode` | `dry-run` | `dry-run`과 `report-only`는 탐지와 audit만 하고, `enforce`는 변환/차단을 적용합니다. `policy.mode`가 `mode`보다 우선합니다 |
|
|
192
|
+
| `target.type` / `target.adapter` | `llm-http` / `openai-compatible` | upstream 프로토콜: `openai-compatible`, `vllm-openai`, `ollama`, `llama-cpp`. 알 수 없는 type은 fail-closed로 처리됩니다 |
|
|
193
|
+
| `target.upstream` | `http://127.0.0.1:9999` | proxy가 요청을 전달하는 유일한 upstream(절대 URL 요청 대상은 거부됩니다) |
|
|
194
|
+
| `proxy.host` / `proxy.port` | `127.0.0.1` / `11016` | proxy 바인드 주소. 아래 remote 바인딩 참고 |
|
|
195
|
+
| `responseProtection.enabled` | `false` | upstream JSON 응답을 검사합니다. `failureMode: fail-closed`는 비JSON/압축/대용량 응답을 거부합니다 |
|
|
196
|
+
| `responseProtection.maxBytes` | `1048576` | 응답 크기 상한 — `failureMode: allow`에서도 적용됩니다 |
|
|
197
|
+
| `streaming.requestMode` | `block` | `block`은 스트리밍을 501로 차단하고, `inspect`는 SSE/NDJSON 응답을 stream-filter하며, `pass-through`는 검사 없이 전달합니다(audit 기록). Ollama chat/generate는 `stream: false`가 없으면 스트리밍으로 간주됩니다 |
|
|
198
198
|
| `streaming.responseMode` | `enforce` | 검사된 스트림에 적용되는 enforcement 모드(`dry-run`/`report-only`/`enforce`) |
|
|
199
|
-
| `streaming.maxMatchBytes` | `256` | cross-frame 매칭
|
|
200
|
-
| `limits.maxRequestBytes` | `1048576` | 요청 바디 상한
|
|
201
|
-
| `limits.upstreamTimeoutMs` | `120000` | upstream 타임아웃
|
|
202
|
-
| `policy.presets` | `korean-pii`, `secrets-only`, `llm-redact` | 병합되는 프리셋 action
|
|
199
|
+
| `streaming.maxMatchBytes` | `256` | cross-frame 매칭 윈도우. 이보다 긴 단일 매치는 프레임에 걸쳐 나뉠 수 있습니다 |
|
|
200
|
+
| `limits.maxRequestBytes` | `1048576` | 요청 바디 상한(초과 시 413) |
|
|
201
|
+
| `limits.upstreamTimeoutMs` | `120000` | upstream 타임아웃(만료 시 504) |
|
|
202
|
+
| `policy.presets` | `korean-pii`, `secrets-only`, `llm-redact` | 병합되는 프리셋 action. 강화는 가능하지만 약화는 불가합니다 |
|
|
203
203
|
| `policy.actions` | `card: block` | type별 action: `allow`/`redact`/`mask`/`tokenize`/`encrypt`/`block` |
|
|
204
|
-
| `filters.customRules` | `[]` | 추가 정규식 규칙
|
|
205
|
-
| `keys.provider` / `keys.keyFile` | `local` / `.haechi/dev.keys.json` | 개발 전용 소프트웨어 키
|
|
206
|
-
| `audit.path` | `.haechi/audit.jsonl` | hash chain JSONL audit
|
|
207
|
-
| `tokenVault.revealPolicy` | `disabled` | 수동 reveal 게이트
|
|
208
|
-
| `tokenVault.retentionDays` | `30` | 만료된 token은 vault 쓰기 시 또는 `haechi token-purge --expired`로
|
|
209
|
-
| `tokenVault.deterministic` / `deterministicTypes` / `detokenizeResponses` | `false` / `null` / `false` | 토큰 왕복
|
|
210
|
-
| `privacy.profile` | `null` | `kr-pipa`, `eu-gdpr`, `us-general` 기준 action
|
|
204
|
+
| `filters.customRules` | `[]` | 추가 정규식 규칙(ReDoS 검사: 중첩 한정자/역참조 불가) |
|
|
205
|
+
| `keys.provider` / `keys.keyFile` | `local` / `.haechi/dev.keys.json` | 개발 전용 소프트웨어 키(0600). `external`은 프로그래밍 방식으로 crypto provider를 주입해야 합니다 |
|
|
206
|
+
| `audit.path` | `.haechi/audit.jsonl` | hash chain JSONL audit 로그. `haechi audit-verify`로 검증합니다 |
|
|
207
|
+
| `tokenVault.revealPolicy` | `disabled` | 수동 reveal 게이트(`local-dev`로 활성화하며, 모든 결정이 audit에 기록됩니다) |
|
|
208
|
+
| `tokenVault.retentionDays` | `30` | 만료된 token은 vault 쓰기 시 또는 `haechi token-purge --expired`로 삭제됩니다 |
|
|
209
|
+
| `tokenVault.deterministic` / `deterministicTypes` / `detokenizeResponses` | `false` / `null` / `false` | 토큰 왕복(위 참고) |
|
|
210
|
+
| `privacy.profile` | `null` | `kr-pipa`, `eu-gdpr`, `us-general` 기준 action(강화 전용) |
|
|
211
211
|
| `mcp.allowedMethods` | `initialize`, `tools/call`, `resources/read`, `prompts/get` | `mcp-stdio`/`mcp-wrap`에서 클라이언트가 호출할 수 있는 method allowlist |
|
|
212
|
-
| `auth.provider` / `auth.store` | `none` / `.haechi/auth.json` | `none`/`bearer`/`external`. Bearer token은 keyed-HMAC 해시로
|
|
213
|
-
| `policy.profiles` / `policy.profileBinding` | — | 클라이언트별 named policy profile
|
|
214
|
-
| `policy.modelAllowlist` / `policy.rate` | — | 허용된 모델 이름
|
|
212
|
+
| `auth.provider` / `auth.store` | `none` / `.haechi/auth.json` | `none`/`bearer`/`external`. Bearer token은 keyed-HMAC 해시로 저장됩니다(0600) |
|
|
213
|
+
| `policy.profiles` / `policy.profileBinding` | — | 클라이언트별 named policy profile. scope → label → 필수 `default` 순으로 바인딩됩니다 |
|
|
214
|
+
| `policy.modelAllowlist` / `policy.rate` | — | 허용된 모델 이름(그 외 403), identity별 분당 요청 rate limit(429). profile별로도 설정할 수 있습니다 |
|
|
215
215
|
|
|
216
|
-
위 표는 빠른
|
|
216
|
+
위 표는 빠른 참고용입니다. 키별 전체 레퍼런스(타입, 검증 규칙, 프리셋, action 강도, 자주 쓰는 설정)는 [`docs/current/configuration.md`](docs/current/configuration.md)에 있으며, CLI에서도 축약본을 출력합니다.
|
|
217
217
|
|
|
218
218
|
```bash
|
|
219
219
|
haechi config # 설정 가이드
|
|
@@ -224,68 +224,68 @@ haechi status # 현재 설정의 실제 적용 상태
|
|
|
224
224
|
|
|
225
225
|
### loopback 밖으로 바인딩 (0.0.0.0)
|
|
226
226
|
|
|
227
|
-
proxy는 CLI 플래그를 명시적으로 전달하지 않으면 non-loopback 호스트를
|
|
227
|
+
proxy는 CLI 플래그를 명시적으로 전달하지 않으면 non-loopback 호스트를 거부합니다. 설정 파일에 `proxy.host: "0.0.0.0"`만 지정해도 의도적으로 시작되지 않습니다(설정 파일을 복사하더라도 게이트웨이가 저절로 노출되지 않도록 하기 위함입니다).
|
|
228
228
|
|
|
229
229
|
```bash
|
|
230
230
|
haechi proxy --config haechi.config.json --host 0.0.0.0 --allow-remote-bind
|
|
231
231
|
```
|
|
232
232
|
|
|
233
|
-
**proxy는
|
|
233
|
+
**proxy는 bearer 클라이언트 인증을 제공합니다**(`auth.provider: bearer`, 0.6에서 출시). 해시 기반 token 저장소, identity별 policy profile, model allowlist, identity별 rate limit을 함께 제공합니다([인증 및 클라이언트별 통제](#인증-및-클라이언트별-통제) 참고). 기본값 `auth.provider: none`은 proxy를 인증 없이 두므로, `none`에서는 포트에 접근할 수 있는 사람은 누구나 upstream과 token round-trip 경로를 쓸 수 있습니다. 내장 rate limit은 단일 프로세스(인메모리, 프로세스별)이므로, 여러 replica는 공유 limiter를 앞에 두어야 합니다. `--allow-remote-bind`는 어느 경우에도 명시적인 네트워크 통제가 있을 때만 사용하십시오.
|
|
234
234
|
|
|
235
|
-
- **컨테이너**: 컨테이너
|
|
236
|
-
- **LAN/원격**: 방화벽, VPN(예: Tailscale), 또는 인증 reverse proxy를 앞에
|
|
235
|
+
- **컨테이너**: 컨테이너 안에서 `0.0.0.0`으로 바인딩하는 것은 일반적인 패턴입니다 — 포트 매핑에서 노출을 제한하세요(예: `-p 127.0.0.1:11016:11016`)
|
|
236
|
+
- **LAN/원격**: 방화벽, VPN(예: Tailscale), 또는 인증 reverse proxy를 앞에 두세요
|
|
237
237
|
|
|
238
238
|
## Privacy Profiles
|
|
239
239
|
|
|
240
|
-
Haechi는 로컬 정책 부트스트래핑을 위한 기본
|
|
240
|
+
Haechi는 로컬 정책 부트스트래핑을 위한 지역별 기본 Privacy Profiles를 제공합니다.
|
|
241
241
|
|
|
242
242
|
- `kr-pipa`
|
|
243
243
|
- `eu-gdpr`
|
|
244
244
|
- `us-general`
|
|
245
245
|
|
|
246
|
-
`haechi.config.json`에서 `privacy.profile`을 설정하면 집행 전에 해당 프로필의 기본 action이
|
|
246
|
+
`haechi.config.json`에서 `privacy.profile`을 설정하면 집행 전에 해당 프로필의 기본 action이 적용됩니다. 이 프로필은 엔지니어링 기본값이며, 법적 자문이 아닙니다.
|
|
247
247
|
|
|
248
248
|
## 보안 노트
|
|
249
249
|
|
|
250
|
-
- 이 프로젝트는 컴플라이언스를 보장하지
|
|
251
|
-
-
|
|
252
|
-
- Audit 이벤트에는 원시 prompt, tool result, secret,
|
|
253
|
-
- 알 수 없거나 잘못된 정책/설정 오류는 집행 경로에서 fail-closed로
|
|
254
|
-
- Response protection은 명시적인 allow 정책이
|
|
255
|
-
- Token reveal
|
|
256
|
-
- `haechi init --force`는 로컬 키를
|
|
257
|
-
- Privacy profile은 명시적으로 더 엄격한 사용자 action을 강화할 수는
|
|
258
|
-
- 탐지는 문자열 값, JSON 숫자(예: 카드 번호), 객체 키 이름을
|
|
259
|
-
- Audit tail truncation: `audit.anchor.mode: file`을 설정하면(추가 전용/별도 미디어에서) `haechi audit-verify --anchor`가 마지막 anchor
|
|
260
|
-
- Key custody: `keys.provider: external`은 주입된 `cryptoProvider`를
|
|
261
|
-
- Release integrity: 배포된 tarball에는 npm provenance attestation이
|
|
262
|
-
- 1.0 authProvider 플러그인 샌드박스는 서명된 플러그인을 `worker_threads` worker에서
|
|
263
|
-
- 자체 네트워크 통제와 인증을 앞에 두지
|
|
250
|
+
- 이 프로젝트는 컴플라이언스를 보장하지 않습니다.
|
|
251
|
+
- 로컬 crypto provider는 Node `crypto`의 AES-256-GCM과 로컬 소프트웨어 키 파일을 사용합니다.
|
|
252
|
+
- Audit 이벤트에는 원시 prompt, tool result, secret, PII 값이 들어가서는 안 됩니다.
|
|
253
|
+
- 알 수 없거나 잘못된 정책/설정 오류는 집행 경로에서 fail-closed로 처리됩니다.
|
|
254
|
+
- Response protection은 명시적인 allow 정책이 없으면 비JSON, 잘못된 JSON, 압축, 대용량 응답에 대해 fail-closed로 처리됩니다.
|
|
255
|
+
- Token reveal과 purge 결정은 audit 로그에 기록됩니다(token id와 결정만 기록하고 평문은 기록하지 않습니다). 만료된 token은 vault 변경 시 또는 `haechi token-purge --expired`로 제거됩니다.
|
|
256
|
+
- `haechi init --force`는 로컬 키를 교체합니다. 기존 키는 `retired` 상태로 보관되어, 기존 암호문과 token vault 레코드를 `kid`로 복호화할 수 있습니다.
|
|
257
|
+
- Privacy profile은 명시적으로 더 엄격한 사용자 action을 강화할 수는 있어도 약화할 수는 없습니다.
|
|
258
|
+
- 탐지는 문자열 값, JSON 숫자(예: 카드 번호), 객체 키 이름을 검사합니다. Base64/URL 인코딩된 값과 URL 쿼리 스트링은 검사하지 않습니다.
|
|
259
|
+
- Audit tail truncation: `audit.anchor.mode: file`을 설정하면(추가 전용/별도 미디어에서) `haechi audit-verify --anchor`가 마지막 anchor 이후의 꼬리 레코드 삭제를 탐지합니다. 같은 쓰기 가능 파일시스템에서는 공격자가 두 파일을 함께 잘라낼 수 있습니다.
|
|
260
|
+
- Key custody: `keys.provider: external`은 주입된 `cryptoProvider`를 허용하며, `assertCryptoProviderConformance`로 adapter를 검증합니다. envelope 암호화 KMS adapter는 `haechi-crypto-kms` 위성(`satellites/crypto-kms/`)이 제공합니다.
|
|
261
|
+
- Release integrity: 배포된 tarball에는 npm provenance attestation이 포함되고, GitHub release asset에는 sigstore attestation과 `SHA256SUMS`가 추가됩니다(`gh attestation verify`와 `node scripts/release-checksums.mjs --check`로 검증합니다).
|
|
262
|
+
- 1.0 authProvider 플러그인 샌드박스는 서명된 플러그인을 `worker_threads` worker에서 실행합니다. 이는 메모리/크래시 격리와 데이터 최소화(credential 슬라이스만 넘어가고, host가 keyed-HMAC identity를 만듭니다)일 뿐 capability 샌드박스가 **아닙니다**. 악의적인 *서명된* 플러그인은 여전히 `fs`/`net`을 써서 받은 credential을 유출할 수 있습니다. load-bearing 통제는 trust gate(Ed25519 서명 + 운영자 allowlist + 버전 pin/floor + revocation)입니다. **1.1이 이 잔존 위험을 닫습니다.** opt-in `process-isolated` 런타임(`auth.plugin.isolation: "process"`)은 서명된 플러그인을 Node 권한 모델(`--permission`, 부여 0) 하의 자식 프로세스에서 실행하며, fs/net/exec/worker가 커널 수준에서 거부되고, 모든 stdio가 무시되며, `data:` URL로 로드(파일시스템 권한 없음)됩니다 — 진정한 capability 강제입니다. `--allow-net`을 강제하는 Node가 필요하고 그렇지 않으면 **fail closed**합니다. 변경되지 않은 `worker_threads` 모드가 기본으로 유지됩니다. 기본 배선은 dependency injection(`createRuntime(config, providers)`)으로 유지됩니다.
|
|
263
|
+
- 자체 네트워크 통제와 인증을 앞에 두지 않은 채 Haechi를 인터넷에 노출된 운영 LLM 게이트웨이로 사용하지 마세요.
|
|
264
264
|
|
|
265
265
|
## 현재 범위
|
|
266
266
|
|
|
267
|
-
0.1 빠른 시작 범위는 `docs/current/mvp-0.1-implementation-scope.md`에 설명되어
|
|
267
|
+
0.1 빠른 시작 범위는 `docs/current/mvp-0.1-implementation-scope.md`에 설명되어 있습니다.
|
|
268
268
|
|
|
269
|
-
0.2는 로컬 TokenVault, 서명된 policy bundle 커맨드, 플러그인 매니페스트 검증, MCP stdio JSON-RPC 라인 필터 스켈레톤을
|
|
269
|
+
0.2는 로컬 TokenVault, 서명된 policy bundle 커맨드, 플러그인 매니페스트 검증, MCP stdio JSON-RPC 라인 필터 스켈레톤을 추가합니다. `docs/current/release-0.2-implementation-scope.md` 참고.
|
|
270
270
|
|
|
271
|
-
0.3은 로컬 inference 프로토콜 adapter, 선택적 JSON 응답 보호, npm 패키지 메타데이터, 배포 준비 export를
|
|
271
|
+
0.3은 로컬 inference 프로토콜 adapter, 선택적 JSON 응답 보호, npm 패키지 메타데이터, 배포 준비 export를 추가합니다. `docs/current/release-0.3-implementation-scope.md` 참고.
|
|
272
272
|
|
|
273
|
-
0.3.1은 릴리스 안전 게이트, 응답 fail-closed 동작, audit hash chaining, token reveal 거버넌스, provider injection, privacy profile, CI/SBOM/provenance 워크플로 스캐폴딩, 그리고 전용 위협/공유 책임/API 안정성 문서를
|
|
273
|
+
0.3.1은 릴리스 안전 게이트, 응답 fail-closed 동작, audit hash chaining, token reveal 거버넌스, provider injection, privacy profile, CI/SBOM/provenance 워크플로 스캐폴딩, 그리고 전용 위협/공유 책임/API 안정성 문서를 추가합니다.
|
|
274
274
|
|
|
275
|
-
0.3.2는 보안 강화 릴리스이자 첫
|
|
275
|
+
0.3.2는 보안 강화 릴리스이자 첫 npm 개발자 프리뷰 대상입니다. Ollama 암묵적 스트리밍 fail-closed 처리, 감사된 token reveal/purge, 보존 기간 purge, kid 기반 키 교체, 도메인 분리 policy bundle 서명, JSON 숫자/객체 키 탐지, upstream 타임아웃, stale lock 복구, non-enforcing 모드 경고를 담았습니다. `docs/current/release-0.3.2-hardening-scope.md` 참고.
|
|
276
276
|
|
|
277
|
-
0.4.0은 token round-trip(deterministic tokenization + 요청 스코프 응답 detokenization), `mcp-wrap` 양방향 MCP 필터, `status` 및 `audit-verify` 커맨드, report-only injection detection 휴리스틱을 추가하고, 0.6 인증을 위한 PII-safe `identity`/`authProvider` 계약을
|
|
277
|
+
0.4.0은 token round-trip(deterministic tokenization + 요청 스코프 응답 detokenization), `mcp-wrap` 양방향 MCP 필터, `status` 및 `audit-verify` 커맨드, report-only injection detection 휴리스틱을 추가하고, 0.6 인증을 위한 PII-safe `identity`/`authProvider` 계약을 예약합니다. `docs/current/release-0.4-implementation-scope.md` 참고.
|
|
278
278
|
|
|
279
|
-
0.5.0은 SSE/NDJSON 스트리밍 응답 검사를
|
|
279
|
+
0.5.0은 SSE/NDJSON 스트리밍 응답 검사를 추가합니다. `streaming.requestMode: "inspect"`가 bounded sliding buffer로 응답을 stream-filter하여 프레임에 걸쳐 나뉜 PII도 잡아냅니다(`streaming.maxMatchBytes`). `docs/current/release-0.5-implementation-scope.md` 참고.
|
|
280
280
|
|
|
281
|
-
0.6.0은 인증과 클라이언트별 통제를
|
|
281
|
+
0.6.0은 인증과 클라이언트별 통제를 추가합니다. 해시 기반 token 저장소와 `haechi auth` CLI를 갖춘 내장 bearer auth, identity scope/label로 바인딩되는 named policy profile, model allowlisting, identity별 rate limiting을 제공하며, audit 로그에는 PII-safe identity가 기록됩니다. `docs/current/release-0.6-implementation-scope.md` 참고.
|
|
282
282
|
|
|
283
|
-
0.7.0은 운영 강화(ops-hardening)
|
|
283
|
+
0.7.0은 운영 강화(ops-hardening) 릴리스입니다. 꼬리 절단을 탐지하는 audit head-hash anchoring(`audit.anchor`), `assertCryptoProviderConformance`와 reference KMS adapter를 포함한 강화된 외부 `cryptoProvider` 계약, 서명·체크섬된 GitHub release artifact를 담았습니다. `docs/current/release-0.7-implementation-scope.md` 참고.
|
|
284
284
|
|
|
285
|
-
0.8.0은 `haechi-*` 에코시스템을
|
|
285
|
+
0.8.0은 `haechi-*` 에코시스템을 세웁니다. npm workspaces 모노레포(core는 unscoped `haechi`를 유지하고, zero runtime dependency를 패킹 매니페스트 CI 게이트로 강제)와 첫 두 위성 — [`haechi-crypto-kms`](satellites/crypto-kms/)(실제 AWS KMS 클라이언트 기반 envelope 암호화. AWS SDK는 optional peer)와 [`haechi-auth-jwt`](satellites/auth-jwt/)(헤드리스 JWKS bearer 검증, `node:` 전용)를 추가합니다. 각각 자체 provenance + sigstore attest 워크플로로 독립 발행합니다. `docs/current/release-0.8-implementation-scope.md` 참고.
|
|
286
286
|
|
|
287
|
-
0.9.0은 관측성(observability) + 대화형 인증
|
|
287
|
+
0.9.0은 관측성(observability) + 대화형 인증 테마입니다. 두 개의 새 위성 — [`haechi-dashboard`](satellites/dashboard/)(audit 로그와 hash chain 상태를 보는 zero-dependency 읽기 전용 `node:http` audit 뷰어. anti-DNS-rebinding Host allowlist, 엄격한 CSP/Trusted Types, fail-closed loopback/remote-bind 가드 포함)와 [`haechi-auth-oidc`](satellites/auth-oidc/)(대시보드의 사람 로그인을 담당하는 대화형 OIDC 세션 브로커 — authorization-code + PKCE + 서버측 세션)를 추가합니다. 기존 위성도 additive minor를 발행합니다. `haechi-auth-jwt@0.2.0`은 재사용 가능한 JWS 검증기(`createJwtVerifier`)를 export하고, `haechi-crypto-kms@0.2.0`은 GCP/Azure/Vault 백엔드를 추가합니다. core는 `0.9.0`으로 bump되며, 현재 이벤트 출력을 바꾸지 않는 심층 방어인 `FORBIDDEN_KEYS` audit 새니타이즈 강화만 포함합니다. `docs/current/release-0.9-implementation-scope.md` 참고.
|
|
288
288
|
|
|
289
|
-
1.0.0은 **첫 stable
|
|
289
|
+
1.0.0은 **첫 stable 릴리스**입니다. strict semver 하의 frozen API 계약을 선언합니다. `package.json`의 `exports` 표면, CLI의 기계 판독 동작, audit event schema(중첩 sub-schema와 `schemaVersion` 포함), config key shape이 모두 major 버전 계약의 일부이며, `tests/api-contract.test.mjs`가 이를 가드하고, 문서화된 deprecation 정책(`HAECHI_DEPRECATION_*` 런타임 경고, 제거는 다음 major에서만)과 공개된 취약점에 대한 in-minor 보안 예외 하나가 이를 규율합니다([`docs/current/api-stability.md`](docs/current/api-stability.md) 참고). 1.0은 또한 dynamic-loading 금지를 **좁게** 해제합니다 — `authProvider` 플러그인에 한해, Ed25519 서명(trust-anchor 전용 키 해석, entry-hash 바인딩, 버전 pin/floor, revocation, 서명 윈도우를 갖춘 비대칭 `node:crypto` 검증)에 capability-gated, `worker_threads` 격리, 완전 감사되는 플러그인 샌드박스를 허용합니다. dependency injection(`createRuntime(config, providers)`)이 기본으로 유지됩니다. **정직한 잔존 위험:** worker는 메모리/크래시 격리와 데이터 최소화일 뿐 capability 샌드박스가 아니므로, 악의적인 *서명된* 플러그인은 여전히 `fs`/`net`을 써서 받은 credential 슬라이스를 유출할 수 있습니다. 따라서 load-bearing 통제는 trust gate이며, 진정한 capability 강제(child-process + Node permission model)는 1.x 목표입니다. 네 개의 `haechi-*` 위성(`haechi-auth-jwt@0.2.1`, `haechi-crypto-kms@0.2.1`, `haechi-dashboard@0.1.2`, `haechi-auth-oidc@0.1.2`)은 pre-1.0으로 유지되고 독립적으로 버저닝하며, `haechi` peer 범위를 `>=0.8.0 <2.0.0`으로 넓혀 core 1.0.0이 그 설치를 깨뜨리지 않게 합니다. `docs/current/release-1.0-implementation-scope.md` 참고.
|
|
290
290
|
|
|
291
|
-
1.1.0은 가장 많이
|
|
291
|
+
1.1.0은 가장 많이 거론되던 1.0의 정직한 잔존 위험을 **진정한 플러그인 capability 강제**로 닫습니다. 새 opt-in `process-isolated` authProvider 런타임(`auth.plugin.isolation: "process"`)은 서명된 플러그인을 Node 권한 모델(`--permission`, **부여 0**) 하의 자식 프로세스에서 실행합니다 — `data:` URL 로드(파일시스템 권한 없음), `stdio: ['ignore','ignore','ignore','ipc']`, 정화된 env. `--allow-net`을 강제하는 Node에서 커널이 플러그인의 `fs`/`net`/`fetch`/`dns`/`child_process`/`worker`는 물론 `process.binding('tcp_wrap')` 우회까지 거부하므로, 악의적 서명 플러그인은 받은 credential을 유출할 수 없습니다. 네트워크 봉쇄는 커널의 `--allow-net` 거부이며(삭제 가능한 JS 하니스가 아닙니다), 기본값 `netEnforcement: "require-permission"`은 `--allow-net`이 없는 Node에서 **fail closed**(생성 거부)합니다. 커스텀 자격증명 플러그인의 경우, **호스트**가 운영자 선언 키 자료를 SSRF 강화 코어 가드(`haechi/ssrf`)로 가져와 IPC로 주입하므로 플러그인은 URL을 직접 지정하지 않습니다. spawn-storm 서킷 브레이커가 재spawn을 제한합니다. 변경되지 않은 1.0 `worker_threads` 모드가 기본으로 유지되며, `process-isolated`는 additive + opt-in(strict semver 하의 **마이너**)입니다. `docs/current/release-1.1-implementation-scope.md` 참고.
|
package/README.md
CHANGED
|
@@ -230,7 +230,7 @@ The proxy refuses non-loopback hosts unless the CLI flag is given explicitly —
|
|
|
230
230
|
haechi proxy --config haechi.config.json --host 0.0.0.0 --allow-remote-bind
|
|
231
231
|
```
|
|
232
232
|
|
|
233
|
-
**The proxy
|
|
233
|
+
**The proxy ships bearer client authentication** (`auth.provider: bearer`, shipped in 0.6): a hashed token store, per-identity policy profiles, a model allowlist, and a per-identity rate limit (see [Authentication & Per-Client Controls](#authentication--per-client-controls)). The default `auth.provider: none` leaves the proxy unauthenticated, so with `none` anyone who can reach the port can use your upstream and the token round-trip path. The built-in rate limit is single-process (in-memory, per-process) — front multiple replicas with a shared limiter. Use `--allow-remote-bind` only behind explicit network controls regardless:
|
|
234
234
|
|
|
235
235
|
- **Containers**: binding `0.0.0.0` inside a container is the normal pattern — restrict exposure at the port mapping, e.g. `-p 127.0.0.1:11016:11016`
|
|
236
236
|
- **LAN/remote**: put a firewall, VPN (e.g. Tailscale), or an authenticating reverse proxy in front
|
|
@@ -248,7 +248,7 @@ Set `privacy.profile` in `haechi.config.json` to apply the profile's default act
|
|
|
248
248
|
## Security Notes
|
|
249
249
|
|
|
250
250
|
- This project is not a compliance guarantee.
|
|
251
|
-
- The
|
|
251
|
+
- The local crypto provider uses Node `crypto` with AES-256-GCM and a local software-key file.
|
|
252
252
|
- Audit events must not contain raw prompt, tool result, secret, or PII values.
|
|
253
253
|
- Unknown or invalid policy/config errors should fail closed in enforcement paths.
|
|
254
254
|
- Response protection fails closed for non-JSON, invalid JSON, compressed, or oversized responses unless an explicit allow policy is configured.
|
package/SECURITY.md
CHANGED
|
@@ -8,7 +8,7 @@ Release risk tracking is maintained in `docs/current/risk-register-release-gate.
|
|
|
8
8
|
|
|
9
9
|
## Supported Versions
|
|
10
10
|
|
|
11
|
-
Only the current `
|
|
11
|
+
Only the current `1.x` stable line is considered in scope. From 1.0 the public API is a frozen contract under strict semver, with a documented deprecation policy and a single in-minor security exception for disclosed vulnerabilities (see `docs/current/api-stability.md`). The four `haechi-*` satellites are pre-1.0 and version independently of core.
|
|
12
12
|
|
|
13
13
|
## Reporting
|
|
14
14
|
|
|
@@ -16,15 +16,17 @@ Report suspected vulnerabilities privately to the repository maintainer. Do not
|
|
|
16
16
|
|
|
17
17
|
## Security Invariants
|
|
18
18
|
|
|
19
|
-
- Audit output must not contain raw sensitive payload values.
|
|
20
|
-
- Audit output must carry a SHA-256 hash chain for local tamper detection.
|
|
21
|
-
- Encryption must bind ciphertext to canonical AAD.
|
|
22
|
-
- Policy enforcement must prefer blocking over leaking plaintext when configuration is invalid.
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
19
|
+
- Audit output must not contain raw sensitive payload values; `FORBIDDEN_KEYS` guards against plaintext prompt, tool-result, secret, or PII values reaching the audit log.
|
|
20
|
+
- Audit output must carry a SHA-256 hash chain for local tamper detection; `audit.anchor` head-hash anchoring on append-only/separate media detects tail truncation back to the last anchor.
|
|
21
|
+
- Encryption must bind ciphertext to canonical AAD; the local crypto provider uses AES-256-GCM over a software-key file, and `keys.provider: external` requires an injected `cryptoProvider`.
|
|
22
|
+
- Policy enforcement must prefer blocking over leaking plaintext when configuration is invalid (fail-closed), including an unknown `target.type`.
|
|
23
|
+
- Policies only get stronger: preset/action merges and privacy profiles may strengthen but never weaken an explicit action (`ACTION_STRENGTH`).
|
|
24
|
+
- Proxy listeners must stay loopback-only unless remote binding is explicitly enabled (`--allow-remote-bind`) and the deployment supplies network access controls.
|
|
25
|
+
- Streaming responses are inspected only within bounds and opt-in: `streaming.requestMode: "inspect"` stream-filters SSE/NDJSON with a bounded cross-frame sliding buffer; the default `block` refuses streaming fail-closed, and `pass-through` is an explicit, audited opt-out.
|
|
26
|
+
- Response protection fails closed for non-JSON, invalid JSON, compressed, or oversized responses unless an explicit allow policy is configured.
|
|
27
|
+
- Client authentication is available: `auth.provider` of `bearer` (built-in hashed token store), `external` (injected `authProvider`), or `plugin` (a signed, sandboxed `authProvider`); identity in the audit log is keyed-HMAC, never raw subject/issuer. The default `none` leaves the proxy unauthenticated. The built-in rate limit is single-process (per-process).
|
|
28
|
+
- Token reveal must be disabled by default and enabled only for explicit local development workflows; reveal/purge decisions are audited by token id, never plaintext.
|
|
29
|
+
- Dynamic plugin execution is lifted **narrowly** for `authProvider` plugins only, gated by an Ed25519 signature, an operator trust-anchor allowlist, version pin/floor, revocation, and a validity window. The plugin runs in a sandbox: `worker_threads`-isolated (1.0, memory/crash isolation + data-minimization) or, opt-in, `process-isolated` (1.1, a child under the Node `--permission` model with kernel-enforced fs/net/exec/worker denial on a `--allow-net` Node, fail-closed otherwise). Plugin manifests declare capabilities (e.g. credential reads, network egress). All other plugin/provider kinds stay dependency-injection-only.
|
|
28
30
|
|
|
29
31
|
## Local Development Keys
|
|
30
32
|
|