haechi 0.3.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.
Files changed (54) hide show
  1. package/LICENSE +154 -0
  2. package/README.md +102 -0
  3. package/SECURITY.md +31 -0
  4. package/docs/README.md +35 -0
  5. package/docs/current/api-stability.ko.md +48 -0
  6. package/docs/current/api-stability.md +48 -0
  7. package/docs/current/expert-gap-review-ai-llm-mcp-encryption.ko.md +107 -0
  8. package/docs/current/expert-gap-review-ai-llm-mcp-encryption.md +107 -0
  9. package/docs/current/global-privacy-compliance-review.ko.md +110 -0
  10. package/docs/current/global-privacy-compliance-review.md +110 -0
  11. package/docs/current/initial-plan-ai-llm-mcp-encryption.ko.md +214 -0
  12. package/docs/current/initial-plan-ai-llm-mcp-encryption.md +214 -0
  13. package/docs/current/mvp-0.1-implementation-scope.ko.md +79 -0
  14. package/docs/current/mvp-0.1-implementation-scope.md +79 -0
  15. package/docs/current/open-source-modular-architecture.ko.md +387 -0
  16. package/docs/current/open-source-modular-architecture.md +387 -0
  17. package/docs/current/prd-ai-llm-mcp-encryption.ko.md +260 -0
  18. package/docs/current/prd-ai-llm-mcp-encryption.md +262 -0
  19. package/docs/current/privacy-filtering-policy-draft.ko.md +307 -0
  20. package/docs/current/privacy-filtering-policy-draft.md +307 -0
  21. package/docs/current/release-0.2-implementation-scope.ko.md +46 -0
  22. package/docs/current/release-0.2-implementation-scope.md +46 -0
  23. package/docs/current/release-0.3-implementation-scope.ko.md +86 -0
  24. package/docs/current/release-0.3-implementation-scope.md +86 -0
  25. package/docs/current/release-0.3.2-hardening-scope.ko.md +64 -0
  26. package/docs/current/release-0.3.2-hardening-scope.md +64 -0
  27. package/docs/current/release-0.4-implementation-scope.ko.md +121 -0
  28. package/docs/current/release-0.4-implementation-scope.md +121 -0
  29. package/docs/current/release-process.ko.md +48 -0
  30. package/docs/current/release-process.md +48 -0
  31. package/docs/current/risk-register-release-gate.ko.md +154 -0
  32. package/docs/current/risk-register-release-gate.md +154 -0
  33. package/docs/current/shared-responsibility.ko.md +38 -0
  34. package/docs/current/shared-responsibility.md +38 -0
  35. package/docs/current/threat-model.ko.md +68 -0
  36. package/docs/current/threat-model.md +68 -0
  37. package/examples/llm-prompt-filtering/input.json +13 -0
  38. package/examples/plugins/custom-filter.plugin.json +29 -0
  39. package/haechi.config.example.json +70 -0
  40. package/package.json +74 -0
  41. package/packages/audit/index.mjs +262 -0
  42. package/packages/cli/bin/haechi.mjs +341 -0
  43. package/packages/cli/runtime.mjs +287 -0
  44. package/packages/core/index.mjs +309 -0
  45. package/packages/crypto/index.mjs +142 -0
  46. package/packages/filter/index.mjs +189 -0
  47. package/packages/mcp-stdio/index.mjs +105 -0
  48. package/packages/plugin/index.mjs +83 -0
  49. package/packages/policy/index.mjs +165 -0
  50. package/packages/policy-bundle/index.mjs +91 -0
  51. package/packages/privacy-profiles/index.mjs +92 -0
  52. package/packages/protocol-adapters/index.mjs +111 -0
  53. package/packages/proxy/index.mjs +534 -0
  54. package/packages/token-vault/index.mjs +262 -0
@@ -0,0 +1,154 @@
1
+ # Haechi Risk Register and Release Gates
2
+
3
+ - Status: Draft 0.3
4
+ - Date: 2026-06-10
5
+ - Target version: 0.3.2
6
+ - Branch: `irae/risk-resolution`
7
+
8
+ ## 1. Current Assessment
9
+
10
+ 0.3.2 resolves the additional security and operational risks identified during the full 0.3.1 code review, meeting the bar for developer preview. Publishing to GitHub and distributing on npm as a developer preview are permitted. Actual npm publish must pass the following external operator gates: npm account authentication, package ownership, and successful execution of the GitHub release workflow.
11
+
12
+ | Category | Judgment | Rationale |
13
+ |---|---|---|
14
+ | GitHub public | Allowed | Security limitations, threat model, shared responsibility, and developer preview language are documented |
15
+ | GitHub release/tag | Allowed | Must be presented as developer preview, not production-ready |
16
+ | npm developer preview | Conditionally allowed | Requires passing `npm run release:preflight`, then running `release:preflight:npm` and a provenance publish from an authenticated account |
17
+ | npm stable | On hold | Stable label prohibited until 1.0 API stability, production KMS/HSM/Vault reference adapter, and stream-aware enforcement are in place |
18
+ | Production use | Prohibited | 0.3.2 is a self-hosted developer preview; production auth/authz/key custody is the user's responsibility |
19
+
20
+ ## 2. Release Gates
21
+
22
+ | Gate | Target | Criteria | Current Status |
23
+ |---|---|---|---|
24
+ | G0 | GitHub source publication | Tests pass, security limitations documented, no plaintext audit leak | Pass |
25
+ | G1 | GitHub pre-release | P0 code risks resolved, no production-ready language | Pass |
26
+ | G2 | npm developer preview | P0 resolved, preflight/SBOM/provenance paths ready, npm auth confirmed | Conditional Pass |
27
+ | G3 | npm stable | P1 production reference, stream-aware enforcement, API stability hardened | Blocked |
28
+
29
+ ## 3. P0 Distribution-Blocking Risk Status
30
+
31
+ | ID | Risk | Status | Resolution evidence |
32
+ |---|---|---|---|
33
+ | P0-REL-001 | npm authentication/authorization unresolved | External Gate | Gated via `release:preflight:npm`, GitHub release workflow, and `npm publish --provenance --access public`. Actual authentication requires an operator |
34
+ | P0-REL-002 | Proxy exposed to external network | Resolved | Non-loopback bind fails by default; `--allow-remote-bind` must be specified explicitly |
35
+ | P0-REL-003 | Streaming request handling unclear | Resolved | `stream: true` defaults to 501 fail-closed; `streaming.requestMode: "pass-through"` must be set explicitly |
36
+ | P0-REL-004 | `responseProtection` failure mode unclear | Resolved | Non-JSON, invalid JSON, compressed, and oversized responses are fail-closed; explicit allow policies are separated |
37
+ | P0-REL-005 | Local dev key misunderstood as production key | Resolved | `init`, README, and SECURITY warn that the dev-only key is not a production key provider |
38
+ | P0-REL-006 | npm package trust overstated | Resolved | package description, README, and SECURITY updated to reflect experimental developer preview status |
39
+
40
+ ## 4. P1 Security Design Risk Status
41
+
42
+ | ID | Risk | Status | Resolution evidence |
43
+ |---|---|---|---|
44
+ | P1-SEC-001 | KMS/HSM/Vault not supported | Resolved for OSS core | `createRuntime(config, { cryptoProvider })` external crypto provider injection; fails closed if no external provider is supplied |
45
+ | P1-SEC-002 | TokenVault permission model insufficient | Resolved | `revealPolicy: "disabled"` is the default; `--allow-dev-reveal`, metadata export, retention/purge timestamps added |
46
+ | P1-SEC-003 | Audit integrity insufficient | Resolved | JSONL audit SHA-256 hash chain and `verifyAuditChain` |
47
+ | P1-SEC-004 | No plugin runtime | Resolved by gating | Dynamic runtime is rejected; only `manifest-only` plugins pass |
48
+ | P1-SEC-005 | Policy conflict handling insufficient | Resolved | Downgrading a stronger action (e.g., preset block) to a weaker one fails closed on conflict |
49
+ | P1-SEC-006 | Regex-based filter accuracy limited | Resolved for preview | KR RRN checksum, Luhn, and unsafe custom regex restrictions added. ML/classifier plugin is in the stable backlog |
50
+ | P1-SEC-007 | AAD/replay/stream extension insufficient | Resolved for preview | AAD hash mismatch is explicit; streaming is blocked by default. Stream sequence/replay cache required when stream support is introduced |
51
+ | P1-SEC-008 | MCP security contract incomplete | Resolved for preview | JSON-RPC 2.0 required, method allowlist, params/result protection toggles. OAuth resource binding is the responsibility of the external MCP layer |
52
+
53
+ ## 5. P1 Operational/Deployment Risk Status
54
+
55
+ | ID | Risk | Status | Resolution evidence |
56
+ |---|---|---|---|
57
+ | P1-OPS-001 | No CI | Resolved | `.github/workflows/ci.yml` |
58
+ | P1-OPS-002 | No SBOM/provenance | Resolved | `npm run sbom`, `.github/workflows/npm-publish.yml`, `publishConfig.provenance` |
59
+ | P1-OPS-003 | No real vLLM/Ollama/llama.cpp integration tests | Resolved for preview | Env-gated optional local inference integration tests added. CI skips when no external model server is present |
60
+ | P1-OPS-004 | Performance/large payload not measured | Resolved for preview | Request/response byte limits, `npm run bench:payload` |
61
+ | P1-OPS-005 | npm ownership unconfirmed | External Gate | `npm run release:preflight:npm` from an authenticated npm account required; post-publish `npm view haechi version` needed |
62
+
63
+ ## 5.1 Additional Security Review Risk Resolution Status
64
+
65
+ | ID | Risk | Status | Resolution evidence |
66
+ |---|---|---|---|
67
+ | P1-SEC-009 | Proxy absolute-form request target could bypass upstream or enable SSRF | Resolved | Absolute/protocol-relative request targets are rejected as `haechi_invalid_proxy_target`; upstream URL combines only path and search with the fixed upstream |
68
+ | P1-SEC-010 | `responseProtection.maxBytes` checked after full buffering, enabling memory DoS | Resolved | Upstream body is read via stream reader with a byte cap; excess immediately triggers cancel/fail-closed. `failureMode: "allow"` cannot bypass the hard byte cap |
69
+ | P1-SEC-011 | Concurrent writes to audit hash chain could cause sequence/previousHash collision | Resolved | JSONL audit sink serializes hash-chain record building and append via per-sink write queue and lock file |
70
+ | P1-SEC-012 | PII/secrets in JSON object keys could be exposed in audit paths or token metadata | Resolved | Detection `pathText` records `key_<hash>` structured paths instead of raw key names |
71
+ | P1-SEC-013 | Concurrent tokenization/purge in local TokenVault could cause lost updates | Resolved | Vault mutation queue, lock file, and atomic write via temp-file-then-rename applied |
72
+ | P1-SEC-014 | No audit record for `streaming.requestMode: "pass-through"` and `responseProtection.failureMode: "allow"` bypass decisions | Resolved | Decision audit records `streaming_request_pass_through` and `response_unprotected_allowed/blocked` without raw payload |
73
+ | P1-SEC-015 | MCP `allowedMethods` element type validation insufficient | Resolved | Config validation strengthened to allow only non-empty strings |
74
+ | P1-OPS-006 | GitHub Actions major-tag pinning could allow supply-chain drift | Resolved | `checkout`, `setup-node`, and `upload-artifact` pinned to verified commit SHAs |
75
+
76
+ ## 5.2 Second Full Code Review Risk Resolution Status (0.3.2)
77
+
78
+ | ID | Risk | Status | Resolution evidence |
79
+ |---|---|---|---|
80
+ | P0-SEC-016 | Ollama `/api/chat` and `/api/generate` default to streaming when `stream` is omitted, allowing streaming block bypass | Resolved | `streamingDefault` introduced in protocol adapter; requests without explicit `stream: false` are treated as streaming and default to 501 fail-closed |
81
+ | P1-SEC-017 | Token reveal/purge not recorded in audit | Resolved | `auditSink` injected into local TokenVault; `reveal_allowed/denied/failed`, `purge`, and `purge_expired` decision audits recorded (no plaintext) |
82
+ | P1-SEC-018 | Privacy profile could silently weaken user-specified policies | Resolved | `applyPrivacyProfile` compares ACTION_STRENGTH and only allows strengthening |
83
+ | P1-SEC-019 | Decrypt ignores envelope `kid`; `init --force` destroys existing keys, permanently losing vault/ciphertext | Resolved | Key selection based on `kid`; `--force` now performs rotation that preserves existing keys as `retired` |
84
+ | P1-SEC-020 | Policy bundle signing reuses the AES encryption key as an HMAC key, violating key separation | Resolved | Domain-separated signing key derived with `haechi:policy-bundle:signing:v1` |
85
+ | P1-SEC-021 | `retentionDays` only blocks reveal but does not delete expired data | Resolved | Expired tokens are automatically pruned on vault mutation; `purgeExpired()` and `haechi token-purge --expired` added |
86
+ | P1-SEC-022 | No upstream fetch timeout, enabling connection exhaustion | Resolved | `limits.upstreamTimeoutMs` (default 120000) and `504 haechi_upstream_timeout` |
87
+ | P1-SEC-023 | JSON numbers (card numbers) and PII/secrets in object keys not detected or transformed | Resolved | Number leaves and object keys included in detection/transform scope (keys are renamed on enforce) |
88
+ | P1-OPS-007 | Stale lock file causes permanent audit/vault write failure | Resolved | Stale locks older than 30 seconds are automatically stolen and reacquired |
89
+ | P1-OPS-008 | Audit append re-reads the entire file on every write (O(n²)) | Resolved | File tail-chunk read for O(1) append |
90
+ | P2-SEC-024 | Unknown `target.type` silently falls back to openai-compatible | Resolved | Unknown type fails closed at config validation |
91
+ | P2-SEC-025 | Short-value masking exposes most of the value (4 of 5 characters) | Resolved | Values of 8 characters or fewer are fully masked |
92
+ | P2-SEC-026 | Assignment-secret redaction removes the key name as well | Resolved | Lookbehind pattern replaces only the secret value |
93
+ | P2-SEC-027 | MCP notifications receive error responses in violation of the JSON-RPC spec; batch handling unspecified | Resolved | Notifications are dropped; batch is explicitly rejected fail-closed |
94
+ | P2-SEC-028 | Proxy internal error messages exposed to clients | Resolved | Unexpected errors return a generic message; details go to stderr |
95
+ | P2-DOC-005 | Default dry-run + responseProtection off could be mistaken for "protection active" | Resolved | Proxy startup and `protect` output explicitly warn when enforcement is inactive |
96
+
97
+ Base64/encoded-value decode inspection, query-string inspection, and audit tail truncation detection are explicitly excluded and documented in the threat model (0.4+ backlog).
98
+
99
+ ## 6. P2 Product/Documentation Risk Status
100
+
101
+ | ID | Risk | Status | Resolution evidence |
102
+ |---|---|---|---|
103
+ | P2-DOC-001 | Separate threat model document missing | Resolved | `docs/current/threat-model.md` |
104
+ | P2-DOC-002 | Shared responsibility documentation insufficient | Resolved | `docs/current/shared-responsibility.md` |
105
+ | P2-DOC-003 | Region/privacy profile not implemented | Resolved for baseline | `haechi/privacy-profiles`, `privacy.profile` applied at runtime |
106
+ | P2-DOC-004 | No API stability policy | Resolved | `docs/current/api-stability.md` |
107
+
108
+ ## 7. npm Developer Preview Pre-Distribution Checklist
109
+
110
+ Current external npm gate check results:
111
+
112
+ - `npm whoami`: `raeseoklee`
113
+ - `npm view haechi version`: `E404 Not Found`
114
+
115
+ The `haechi` name appears to be available, but package ownership is confirmed only after the first successful publish from an authenticated account. `release:preflight:npm` verifies authentication and blocks duplicate publish of `haechi@<current version>`; E404 before the first publish is treated as a passing condition.
116
+
117
+ 1. `npm run release:preflight`
118
+ 2. `npm run sbom`
119
+ 3. `npm run bench:payload`
120
+ 4. `npm run release:preflight:npm`
121
+ 5. Create GitHub release
122
+ 6. GitHub Actions `Publish npm Developer Preview` succeeds
123
+ 7. Confirm actual published version with `npm view haechi version`
124
+
125
+ ## 8. Remaining Non-Blocking Backlog
126
+
127
+ | Version | Goal | Remaining scope |
128
+ |---|---|---|
129
+ | 0.4.0 | Token round-trip and adoption | Request-scoped response detokenization, deterministic tokenization (derived key), `haechi mcp-wrap` (bidirectional stdio), `haechi audit-verify`/`haechi status`, injection detection type (default allow), PII-safe `identity` field and `authProvider` contract reserved. See `docs/current/release-0.4-implementation-scope.md` |
130
+ | 0.5.0 | Streaming hardening | SSE/NDJSON stream inspection, stream sequence AAD, replay cache, stronger remote deployment guide |
131
+ | 0.6.0 | Auth and operational controls | Built-in bearer auth, per-client policy scope, model allowlist/rate budget, Vault/AWS KMS reference adapter, external append-only audit sink, signed release artifacts, npm org (`@haechi/*`) acquisition |
132
+ | 0.7.0 | Observability | npm workspaces migration, `@haechi/dashboard` read-only audit viewer (hash chain integrity display, summary/search/timeline) |
133
+ | 1.0.0 | Stable API contract | Migration policy, long-term audit schema, plugin sandbox/runtime conformance, and dynamic loading of external auth/classifier packages that pass allowlist/manifest |
134
+
135
+ Dynamic npm package loading is prohibited until the 1.0 plugin sandbox. External providers in 0.4–0.7 are supported only via `createRuntime(config, providers)` programmatic injection.
136
+
137
+ ## 9. Current Permitted Use
138
+
139
+ 0.3.2 is intended for use in the following contexts:
140
+
141
+ - Local development environments
142
+ - Sample payload validation
143
+ - OpenAI-compatible/vLLM/Ollama/llama.cpp proxy PoC
144
+ - Policy/filter/audit pipeline review
145
+ - GitHub code review and security design discussion
146
+ - npm developer preview
147
+
148
+ 0.3.2 is not intended for the following uses:
149
+
150
+ - Production LLM gateway
151
+ - Proxy directly exposed to the internet
152
+ - Processing real customer/patient/payment/authentication data
153
+ - Compliance evidence or legal conformance proof
154
+ - npm stable package
@@ -0,0 +1,38 @@
1
+ # Haechi Shared Responsibility
2
+
3
+ - 문서 상태: Draft 0.1
4
+ - 작성일: 2026-06-10
5
+ - 기준 버전: 0.3.2
6
+
7
+ ## 1. 책임 매트릭스
8
+
9
+ | 영역 | Haechi 제공 | 사용자/운영자 책임 |
10
+ |---|---|---|
11
+ | 로컬 개발 | CLI, default config, dev key 생성 | dev key를 운영/공유 환경에 재사용하지 않음 |
12
+ | 정책 집행 | redact/mask/tokenize/encrypt/block pipeline | 규제/조직 정책에 맞는 action 선택 |
13
+ | HTTP proxy | loopback 기본, remote bind guard, body/response limit | 인증, TLS termination, firewall, upstream auth |
14
+ | Streaming | 기본 차단 | pass-through 사용 시 보호 미적용 위험 수용 |
15
+ | TokenVault | 암호화 저장, reveal 기본 차단, purge | reveal 승인 절차, DSAR/retention 운영 |
16
+ | Audit | 평문 제거, hash chain | append-only storage, backup, 보존 기간, 외부 서명 |
17
+ | Key custody | local dev key, external crypto provider contract | KMS/HSM/Vault adapter 구현, rotation, access review |
18
+ | Plugin | manifest validation, dynamic runtime 차단 | plugin code review, sandbox 제공 전 실행 금지 |
19
+ | MCP | JSON-RPC/method allowlist | MCP server auth, resource consent, env secret allowlist |
20
+ | Privacy profile | KR/EU/US baseline actions | 법률 검토, data residency, cross-border transfer evidence |
21
+
22
+ ## 2. 금지되는 기본 사용
23
+
24
+ - `--allow-remote-bind`를 네트워크 통제 없이 사용
25
+ - `.haechi/dev.keys.json`을 운영 데이터에 사용
26
+ - `streaming.requestMode: "pass-through"`를 보호 적용으로 오해
27
+ - `responseProtection.failureMode: "allow"`를 민감 데이터 경로에 사용
28
+ - `token-reveal --allow-dev-reveal`를 운영 복원 절차로 사용
29
+
30
+ ## 3. 운영 전환 체크리스트
31
+
32
+ 1. 외부 crypto provider 또는 KMS/HSM/Vault adapter를 연결한다.
33
+ 2. proxy 앞단에 인증, TLS, firewall, rate limit을 둔다.
34
+ 3. responseProtection을 켜고 fail-closed를 유지한다.
35
+ 4. streaming endpoint는 별도 stream-aware gateway가 준비되기 전 차단한다.
36
+ 5. audit sink를 append-only 또는 외부 서명 저장소로 보낸다.
37
+ 6. TokenVault reveal 승인/보존/삭제 절차를 문서화한다.
38
+ 7. privacy profile은 법률 검토 결과로 보정한다.
@@ -0,0 +1,38 @@
1
+ # Haechi Shared Responsibility
2
+
3
+ - Status: Draft 0.1
4
+ - Date: 2026-06-10
5
+ - Target version: 0.3.2
6
+
7
+ ## 1. Responsibility Matrix
8
+
9
+ | Area | Haechi provides | User/operator responsibility |
10
+ |---|---|---|
11
+ | Local development | CLI, default config, dev key generation | Do not reuse dev keys in production or shared environments |
12
+ | Policy enforcement | redact/mask/tokenize/encrypt/block pipeline | Select actions appropriate to regulatory and organizational policy |
13
+ | HTTP proxy | Loopback default, remote bind guard, body/response limits | Authentication, TLS termination, firewall, upstream auth |
14
+ | Streaming | Blocked by default | Accept the risk of no protection when using pass-through |
15
+ | TokenVault | Encrypted storage, reveal blocked by default, purge | Reveal approval workflow, DSAR/retention operations |
16
+ | Audit | Plaintext removal, hash chain | Append-only storage, backup, retention period, external signing |
17
+ | Key custody | Local dev key, external crypto provider contract | KMS/HSM/Vault adapter implementation, rotation, access review |
18
+ | Plugin | Manifest validation, dynamic runtime blocked | Plugin code review, do not execute before sandbox is available |
19
+ | MCP | JSON-RPC/method allowlist | MCP server auth, resource consent, env secret allowlist |
20
+ | Privacy profile | KR/EU/US baseline actions | Legal review, data residency, cross-border transfer evidence |
21
+
22
+ ## 2. Prohibited default usage
23
+
24
+ - Using `--allow-remote-bind` without network controls
25
+ - Using `.haechi/dev.keys.json` with production data
26
+ - Treating `streaming.requestMode: "pass-through"` as an applied protection
27
+ - Using `responseProtection.failureMode: "allow"` on sensitive data paths
28
+ - Using `token-reveal --allow-dev-reveal` as a production recovery procedure
29
+
30
+ ## 3. Production transition checklist
31
+
32
+ 1. Connect an external crypto provider or KMS/HSM/Vault adapter.
33
+ 2. Place authentication, TLS, a firewall, and rate limiting in front of the proxy.
34
+ 3. Enable responseProtection and keep it fail-closed.
35
+ 4. Block streaming endpoints until a dedicated stream-aware gateway is ready.
36
+ 5. Send the audit sink to an append-only or externally signed storage backend.
37
+ 6. Document the TokenVault reveal approval, retention, and deletion procedures.
38
+ 7. Calibrate privacy profiles based on legal review findings.
@@ -0,0 +1,68 @@
1
+ # Haechi Threat Model
2
+
3
+ - 문서 상태: Draft 0.1
4
+ - 작성일: 2026-06-10
5
+ - 기준 버전: 0.3.2
6
+
7
+ ## 1. 보호 대상
8
+
9
+ Haechi가 보호하려는 주요 자산은 다음이다.
10
+
11
+ | 자산 | 예시 | 보호 목표 |
12
+ |---|---|---|
13
+ | Prompt/context payload | chat messages, tool arguments, MCP params | 모델/도구/로그로 이동하기 전 정책 집행 |
14
+ | Tool/resource result | MCP result, local inference response | 응답 내 PII/secret 재유출 차단 |
15
+ | TokenVault record | tokenized PII mapping | 저장 시 암호화, reveal 기본 차단 |
16
+ | Audit event | detection metadata, decision summary | 평문 비포함, hash chain 무결성 |
17
+ | Crypto envelope | encrypted segments | canonical AAD binding, key provider 교체성 |
18
+ | Plugin manifest | custom provider/filter declaration | capability disclosure, dynamic runtime 차단 |
19
+
20
+ ## 2. 신뢰 경계
21
+
22
+ | 경계 | 신뢰 수준 | 기본 통제 |
23
+ |---|---|---|
24
+ | CLI local process | 개발자 로컬 신뢰 | dev key 경고, dry-run 기본값 |
25
+ | HTTP proxy listener | 비신뢰 client 입력 | loopback bind 기본, remote bind 명시 플래그 |
26
+ | Upstream model/tool server | 비신뢰 또는 부분 신뢰 | request/response protection, uninspectable response fail-closed |
27
+ | Streaming response | 현재 비검사 영역 | `stream: true` 기본 차단 |
28
+ | MCP stdio peer | 부분 신뢰 | JSON-RPC 2.0 요구, method allowlist |
29
+ | Local filesystem | 부분 신뢰 | local key/token vault 0600, audit hash chain |
30
+ | External provider/plugin | 비신뢰 | provider method contract, plugin manifest-only gate |
31
+
32
+ ## 3. 주요 위협과 통제
33
+
34
+ | 위협 | 영향 | 현재 통제 |
35
+ |---|---|---|
36
+ | 인터넷 노출 proxy | 인증 없는 LLM gateway | non-loopback bind 기본 실패 |
37
+ | streaming 우회 | SSE/NDJSON 평문 유출 | streaming request 기본 실패 |
38
+ | Ollama 암묵 streaming 우회 | `stream` 생략 시 NDJSON 평문 유출 | `/api/chat`·`/api/generate`는 `stream: false` 명시 없으면 streaming으로 간주해 기본 차단 |
39
+ | 비JSON/압축/대용량 응답 | responseProtection 우회 | fail-closed response policy |
40
+ | token reveal 남용 | tokenized PII 복원 | revealPolicy 기본 disabled, reveal/purge 결정 audit 기록 |
41
+ | audit 변조 | 감사 증거 신뢰 저하 | SHA-256 hash chain |
42
+ | policy 약화 override | block preset 무력화 | unsafe downgrade conflict 차단, privacy profile은 강화만 가능 |
43
+ | ReDoS custom regex | CPU 고갈 | nested quantifier/backreference 제한 |
44
+ | plugin runtime 착각 | 동적 코드 실행 위험 | manifest-only runtime만 허용 |
45
+ | MCP tool method 오남용 | 예상 밖 tool/resource 접근 | allowedMethods 기반 거부 |
46
+ | key custody 오해 | local dev key 운영 사용 | external crypto provider injection, dev key 경고 |
47
+ | 행 걸린 upstream | proxy 연결 고갈 | `limits.upstreamTimeoutMs` 기본 120s, 초과 시 504 fail |
48
+ | signing/encryption 키 혼용 | key separation 위반 | policy bundle 서명 키를 domain-separated 파생 키로 분리 |
49
+ | JSON number/object key 은닉 | 카드번호 등 비문자열 leaf 미탐지 | number leaf와 object key도 detection/transform 대상 |
50
+
51
+ ## 4. 명시적 제외
52
+
53
+ 0.3.2는 다음을 보장하지 않는다.
54
+
55
+ - 운영 KMS/HSM/Vault adapter 자체 제공
56
+ - internet-facing gateway 인증/인가
57
+ - SSE/NDJSON stream inspection
58
+ - 법적 컴플라이언스 인증
59
+ - 모델 hallucination, prompt injection 완전 방어
60
+ - 외부 MCP server의 OAuth/resource binding 검증
61
+ - base64/URL-encoded 값, 유니코드 난독화 값의 디코딩 후 검사
62
+ - URL query string 내 민감값 검사 (JSON body만 검사)
63
+ - audit hash chain의 tail truncation(꼬리 절단) 탐지 — 체인은 변조/재정렬은 탐지하지만 마지막 N개 레코드 삭제는 외부 보존 사본 없이는 탐지 불가
64
+ - JSON-RPC batch 메시지 처리 (MCP stdio filter는 batch를 fail-closed로 거부)
65
+
66
+ ## 5. 남은 운영 전제
67
+
68
+ 운영 사용자는 Haechi 외부에서 네트워크 접근 제어, upstream 인증, secret injection, key custody, 로그 보존, DSAR/삭제 요청 처리, 법적 transfer 근거를 책임져야 한다.
@@ -0,0 +1,68 @@
1
+ # Haechi Threat Model
2
+
3
+ - Status: Draft 0.1
4
+ - Date: 2026-06-10
5
+ - Target version: 0.3.2
6
+
7
+ ## 1. Assets Under Protection
8
+
9
+ The primary assets Haechi protects are:
10
+
11
+ | Asset | Examples | Protection Goal |
12
+ |---|---|---|
13
+ | Prompt/context payload | chat messages, tool arguments, MCP params | Policy enforcement before data reaches model/tool/logs |
14
+ | Tool/resource result | MCP result, local inference response | Prevent re-leakage of PII/secrets in responses |
15
+ | TokenVault record | tokenized PII mapping | Encrypted at rest, reveal blocked by default |
16
+ | Audit event | detection metadata, decision summary | No plaintext content, hash chain integrity |
17
+ | Crypto envelope | encrypted segments | Canonical AAD binding, swappable key provider |
18
+ | Plugin manifest | custom provider/filter declaration | Capability disclosure, dynamic runtime blocked |
19
+
20
+ ## 2. Trust Boundaries
21
+
22
+ | Boundary | Trust Level | Default Controls |
23
+ |---|---|---|
24
+ | CLI local process | Developer local trust | Dev key warning, dry-run default |
25
+ | HTTP proxy listener | Untrusted client input | Loopback bind by default, remote bind requires explicit flag |
26
+ | Upstream model/tool server | Untrusted or partially trusted | Request/response protection, uninspectable response fail-closed |
27
+ | Streaming response | Currently uninspected | `stream: true` blocked by default |
28
+ | MCP stdio peer | Partially trusted | JSON-RPC 2.0 required, method allowlist |
29
+ | Local filesystem | Partially trusted | Local key/token vault at 0600, audit hash chain |
30
+ | External provider/plugin | Untrusted | Provider method contract, plugin manifest-only gate |
31
+
32
+ ## 3. Key Threats and Controls
33
+
34
+ | Threat | Impact | Current Control |
35
+ |---|---|---|
36
+ | Internet-exposed proxy | Unauthenticated LLM gateway | Non-loopback bind fails by default |
37
+ | Streaming bypass | SSE/NDJSON plaintext leak | Streaming requests fail by default |
38
+ | Ollama implicit streaming bypass | NDJSON plaintext leak when `stream` is omitted | `/api/chat` and `/api/generate` are treated as streaming unless `stream: false` is explicit; blocked by default |
39
+ | Non-JSON / compressed / oversized response | responseProtection bypass | Fail-closed response policy |
40
+ | Token reveal abuse | Restoration of tokenized PII | `revealPolicy` disabled by default; reveal/purge decisions recorded in audit |
41
+ | Audit tampering | Degraded trust in audit evidence | SHA-256 hash chain |
42
+ | Policy-weakening override | Neutralizing block presets | Unsafe downgrade conflicts blocked; privacy profile can only strengthen |
43
+ | ReDoS via custom regex | CPU exhaustion | Nested quantifier/backreference restrictions |
44
+ | Plugin runtime confusion | Dynamic code execution risk | Manifest-only runtime permitted |
45
+ | MCP tool method misuse | Unexpected tool/resource access | Rejected based on `allowedMethods` |
46
+ | Key custody misunderstanding | Local dev key used in production | External crypto provider injection, dev key warning |
47
+ | Hung upstream | Proxy connection exhaustion | `limits.upstreamTimeoutMs` default 120 s; 504 fail on timeout |
48
+ | Signing/encryption key conflation | Key separation violation | Policy bundle signing key isolated as a domain-separated derived key |
49
+ | JSON number / object key concealment | Undetected non-string leaves such as card numbers | Number leaves and object keys included in detection/transform scope |
50
+
51
+ ## 4. Explicit Exclusions
52
+
53
+ 0.3.2 does not guarantee:
54
+
55
+ - A production KMS/HSM/Vault adapter
56
+ - Authentication/authorization for internet-facing gateways
57
+ - SSE/NDJSON stream inspection
58
+ - Legal compliance certification
59
+ - Complete defense against model hallucination or prompt injection
60
+ - OAuth/resource binding validation for external MCP servers
61
+ - Inspection of base64/URL-encoded values or unicode-obfuscated values after decoding
62
+ - Detection of sensitive values in URL query strings (JSON body only)
63
+ - Audit hash chain tail truncation detection — the chain detects tampering and reordering, but deletion of the last N records cannot be detected without an externally preserved copy
64
+ - JSON-RPC batch message processing (the MCP stdio filter rejects batches fail-closed)
65
+
66
+ ## 5. Remaining Operational Assumptions
67
+
68
+ Production users are responsible for the following outside of Haechi: network access control, upstream authentication, secret injection, key custody, log retention, handling DSAR/deletion requests, and establishing a legal transfer basis.
@@ -0,0 +1,13 @@
1
+ {
2
+ "model": "demo-model",
3
+ "messages": [
4
+ {
5
+ "role": "system",
6
+ "content": "You are a helpful assistant."
7
+ },
8
+ {
9
+ "role": "user",
10
+ "content": "Please summarize this customer note. Email: minji.kim@example.com, phone: 010-1234-5678, token: sk_demo_1234567890abcdef1234567890abcdef."
11
+ }
12
+ ]
13
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "haechiPlugin": {
3
+ "id": "example-custom-filter",
4
+ "version": "0.1.0",
5
+ "kind": "filter-engine",
6
+ "runtime": "manifest-only",
7
+ "entrypoint": "./manifest-only",
8
+ "compatibility": {
9
+ "haechiCore": ">=0.2.0 <0.3.0"
10
+ },
11
+ "capabilities": {
12
+ "readsPlaintext": true,
13
+ "writesPlaintext": false,
14
+ "networkEgress": false,
15
+ "fileWrite": false,
16
+ "auditWrite": false,
17
+ "externalSecrets": false
18
+ },
19
+ "dataHandling": {
20
+ "storesPayload": false,
21
+ "retention": "none",
22
+ "logsRawPayload": false
23
+ },
24
+ "tests": {
25
+ "conformance": "./fixtures/conformance.json",
26
+ "negative": "./fixtures/negative.json"
27
+ }
28
+ }
29
+ }
@@ -0,0 +1,70 @@
1
+ {
2
+ "mode": "dry-run",
3
+ "target": {
4
+ "type": "llm-http",
5
+ "adapter": "openai-compatible",
6
+ "upstream": "http://127.0.0.1:9999"
7
+ },
8
+ "proxy": {
9
+ "host": "127.0.0.1",
10
+ "port": 1016
11
+ },
12
+ "responseProtection": {
13
+ "enabled": false,
14
+ "mode": "enforce",
15
+ "failureMode": "fail-closed",
16
+ "allowNonJson": false,
17
+ "allowCompressed": false,
18
+ "maxBytes": 1048576
19
+ },
20
+ "streaming": {
21
+ "requestMode": "block"
22
+ },
23
+ "limits": {
24
+ "maxRequestBytes": 1048576,
25
+ "upstreamTimeoutMs": 120000
26
+ },
27
+ "policy": {
28
+ "mode": "dry-run",
29
+ "presets": [
30
+ "korean-pii",
31
+ "secrets-only",
32
+ "llm-redact"
33
+ ],
34
+ "defaultAction": "redact",
35
+ "actions": {
36
+ "card": "block"
37
+ }
38
+ },
39
+ "filters": {
40
+ "customRules": []
41
+ },
42
+ "keys": {
43
+ "provider": "local",
44
+ "keyFile": ".haechi/dev.keys.json"
45
+ },
46
+ "audit": {
47
+ "sink": "jsonl",
48
+ "path": ".haechi/audit.jsonl"
49
+ },
50
+ "tokenVault": {
51
+ "provider": "local",
52
+ "path": ".haechi/token-vault.json",
53
+ "revealPolicy": "disabled",
54
+ "retentionDays": 30
55
+ },
56
+ "privacy": {
57
+ "profile": null
58
+ },
59
+ "mcp": {
60
+ "allowedMethods": [
61
+ "initialize",
62
+ "tools/call",
63
+ "resources/read",
64
+ "prompts/get"
65
+ ],
66
+ "protectParams": true,
67
+ "protectResults": true,
68
+ "requireJsonRpc": true
69
+ }
70
+ }
package/package.json ADDED
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "haechi",
3
+ "version": "0.3.2",
4
+ "description": "Experimental developer preview for self-hosted AI context enforcement across LLM, MCP, vLLM, Ollama, and agent traffic.",
5
+ "license": "Apache-2.0",
6
+ "type": "module",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/raeseoklee/haechi.git"
10
+ },
11
+ "homepage": "https://github.com/raeseoklee/haechi#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/raeseoklee/haechi/issues"
14
+ },
15
+ "publishConfig": {
16
+ "access": "public",
17
+ "provenance": true
18
+ },
19
+ "keywords": [
20
+ "llm",
21
+ "mcp",
22
+ "ai-security",
23
+ "privacy",
24
+ "redaction",
25
+ "tokenization",
26
+ "ollama",
27
+ "vllm",
28
+ "llama-cpp"
29
+ ],
30
+ "bin": {
31
+ "haechi": "packages/cli/bin/haechi.mjs"
32
+ },
33
+ "exports": {
34
+ ".": "./packages/core/index.mjs",
35
+ "./audit": "./packages/audit/index.mjs",
36
+ "./core": "./packages/core/index.mjs",
37
+ "./crypto": "./packages/crypto/index.mjs",
38
+ "./filter": "./packages/filter/index.mjs",
39
+ "./mcp-stdio": "./packages/mcp-stdio/index.mjs",
40
+ "./plugin": "./packages/plugin/index.mjs",
41
+ "./policy": "./packages/policy/index.mjs",
42
+ "./policy-bundle": "./packages/policy-bundle/index.mjs",
43
+ "./privacy-profiles": "./packages/privacy-profiles/index.mjs",
44
+ "./protocol-adapters": "./packages/protocol-adapters/index.mjs",
45
+ "./proxy": "./packages/proxy/index.mjs",
46
+ "./runtime": "./packages/cli/runtime.mjs",
47
+ "./token-vault": "./packages/token-vault/index.mjs"
48
+ },
49
+ "files": [
50
+ "README.md",
51
+ "SECURITY.md",
52
+ "LICENSE",
53
+ "haechi.config.example.json",
54
+ "packages/",
55
+ "examples/",
56
+ "docs/current/"
57
+ ],
58
+ "scripts": {
59
+ "test": "node --test",
60
+ "pack:dry": "npm pack --dry-run",
61
+ "scan:stale-names": "node scripts/stale-name-scan.mjs",
62
+ "sbom": "node scripts/generate-sbom.mjs",
63
+ "bench:payload": "node scripts/bench-payload.mjs",
64
+ "release:preflight": "node scripts/release-preflight.mjs",
65
+ "release:preflight:npm": "node scripts/release-preflight.mjs --require-npm-auth",
66
+ "haechi": "node packages/cli/bin/haechi.mjs",
67
+ "demo:init": "node packages/cli/bin/haechi.mjs init --force",
68
+ "demo:protect": "node packages/cli/bin/haechi.mjs protect examples/llm-prompt-filtering/input.json --config haechi.config.json",
69
+ "demo:report": "node packages/cli/bin/haechi.mjs report --audit .haechi/audit.jsonl"
70
+ },
71
+ "engines": {
72
+ "node": ">=22"
73
+ }
74
+ }