--- title: branch / feature-frontend-browser-security-boundary-contract source_type: branch-note status: raw id: BR-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-021 kind: project-work-item project: ca-skeleton-frontend-operational-contract work_item: WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-021 inherits: [DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-AUTH-BOUNDARY-001@1, DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-TELEMETRY-001@1] refines: [] overrides: [] depends_on: [WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-008, WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-011, WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-012] contract_packet: 1 branch: feature-frontend-browser-security-boundary-contract parent_branch: related_projects: [ca-skeleton-frontend, ca-skeleton] governing_docs: [raw/project-notes/ca-skeleton-frontend-operational-contract] tags: [branch, ca-skeleton, frontend, security, owasp, static-analysis] created: 2026-07-18 target_merge: status_label: in-progress contract_packet_sha256: 67f39972a793315acd8de19be381ec163d5e8843a539a147103b74c6d4324274 imports: [FE-GATE-002@1, FE-GATE-006@1, FE-GATE-013@1, FE-GATE-019@2, FE-OC-004@1, FE-OC-008@1, FE-OC-010@1, FE-OC-013@1, FE-OC-014@1, FE-OC-016@1, FE-OC-018@1, FE-OC-020@1] accepts_delegations: [DELEG-FE-001@1] --- # branch: feature-frontend-browser-security-boundary-contract > Layer: `raw/branch-notes/` — TODO·결정·진행 기록. 구현 결과는 검증 뒤 `/ingest`로만 추출한다. ## 부모 (필수) [[raw/project-notes/ca-skeleton-frontend-operational-contract]] ## 브랜치 계약 패킷 - **생성 시 프로젝트 개정**: `1` - **패킷 스키마**: `contract_packet: 1` - **완료 조건**: CSP·header·secret·storage·telemetry browser-boundary fixture가 통과한다 ### 상속한 프로젝트 결정 | Decision Ref | Project Summary | Branch Application | Source | |---|---|---|---| | `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-AUTH-BOUNDARY-001@1` | auth lifecycle은 외부 owner가 소유하고 skeleton은 AuthSessionPort만 소비한다 | token·secret browser storage 금지 fixture에 적용 | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | | `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-TELEMETRY-001@1` | telemetry는 best-effort queue와 redaction을 사용하며 sink failure가 UI를 실패시키지 않는다 | telemetry forbidden-attribute leak fixture에 적용 | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | ### 브랜치 지역 결정 > 기존 branch-local 결정은 아래 `## Decision Evidence Map / 결정-근거 매핑`의 D-row가 소유하며 이 packet에서 복제하지 않는다. | Decision ID | Decision | Relation | Supporting Claims | Status | |---|---|---|---|---| ### 선언한 예외 | Override ID | Overrides | Reason | Approval | Status | |---|---|---|---|---| ## 목표 - 이 branch는 project-wide contract `FE-OC-019`(browser bundle에 secret을 넣지 않고 untrusted HTML injection을 기본 금지)의 single owner로서, 이를 *되묻지 않아도 코드를 작성할 수 있는* implementation-ready spec으로 내린다. 근거는 hub [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §13.2(browser security boundary)·§6.1(secret 3-way 구분)·§13.1(secret scan)·§15.1(`FE-GATE-013` security gate)·§15.2(negative fixture)다. - 동시에 `FE-OC-010`(auth session), `FE-OC-013`(storage), `FE-OC-014`(telemetry), `FE-OC-018`(build/bundle supply-chain), `FE-OC-020`(test taxonomy)에 **contribute**한다 — 각 registry의 *schema*는 그 owner branch가 갖고, 본 branch는 그 경계를 넘는 값(secret·token·untrusted HTML·PII)이 브라우저 표면(bundle·env·HTML·storage·telemetry)에 새지 않는지 검증하는 **cross-cutting security fixture와 injection/secret lint+scan**을 소유한다. - 측정 가능한 완료 조건(§20): `CSP/header/secret/storage/telemetry browser-boundary fixtures`. - 이슈: 없음 (스캐폴딩 단계) - PR: 없음 ## 범위 ### 포함 범위 - browser bundle을 public artifact로 간주하고 **secret(client secret·private key·refresh token material)을 bundle·env·HTML에 넣지 않도록** 강제하는 계약 — env registry의 name-based 거부 + source/built-asset secret scan. - **untrusted HTML injection과 dynamic code 실행 기본 금지** — `dangerouslySetInnerHTML`·`eval`·dynamic code(`new Function`)·untrusted script URL의 prohibited import/API lint rule. 불가피한 HTML rendering의 예외 조건(sanitizer owner·allowlist·malicious fixture·CSP interaction evidence) 명세. - bundle이 `unsafe-inline`/`unsafe-eval` 없는 **strict CSP와 호환**되도록 하는 frontend 측 불변식(inline script·inline handler·eval 미의존) + 선언된 security header 정책의 verification fixture. - production public path에 **source map 미배포** 기본 정책. - 위 경계를 넘는 값을 잡는 **cross-cutting security fixture 집합**(secret / storage token-key / telemetry forbidden-attribute / HTML-injection)과 이를 `FE-GATE-013`으로 집계 + `FE-GATE-002`(lint)에 기여. - **`FE-GATE-006`(component gate)의 `FE-OC-019` 슬라이스 fixture 본문 소유** — hub §15.1 이 component gate 의 Covered FE-OC 에 `FE-OC-019` 를 명시했으므로, render 시점에만 관측 가능한 injection 불변식(예외 sanitizer 경로의 malicious fixture + rendered subtree 의 prohibited-API 산출물 부재)은 본 branch 가 component-level fixture 로 소유한다(D8). ### 제외 범위 > 의도적으로 제외한 것. "이건 범위에 없었습니다"라고 답할 근거. - **CSP/HSTS/frame/referrer header의 실제 directive 값(production)** — hosting/backend header owner 소유(hub §13.2). 본 branch는 값이 아니라 *호환성*만 본다. "선언 == 실제"의 **검증 위치**는 2026-07-21 에 `FE-GATE-019@2` 로 확정됐다 — D9 참조. - **hosting header(`Cache-Control`·content-type·security header) 정책의 declared-vs-actual 검증** — release·cache 계약 [[raw/branch-notes/feature-frontend-release-cache-rollback-contract]] 소유(cache 축 `D1`, security-header 축 `D6`). hub §15.1 `FE-GATE-019@2` 가 Covered FE-OC 에 `FE-OC-019` 를 포함하도록 확장돼 security header 도 그 gate 범위다. 본 branch 는 검증 대상 header 정책을 공급한다. - **storage key/version/classification registry schema** — [[raw/branch-notes/feature-frontend-storage-registry-contract]] `FE-OC-013` 소유. 본 branch는 token/secret 저장 시도가 실패하는 security fixture만 갖는다. - **token lifecycle(발급·저장 위치·refresh·rotation·logout)** — 외부 auth owner + [[raw/branch-notes/feature-frontend-auth-session-integration-contract]] `FE-OC-010` 소유. - **telemetry redaction allowlist와 transport-boundary 강제** — [[raw/branch-notes/feature-frontend-observability-logging-trace-contract]] `FE-OC-014` 소유. 본 branch는 forbidden-attribute leak fixture만 기여. - **secret scanner/vulnerability scanner 도구 선택·severity threshold** — supply-chain 계약 [[raw/branch-notes/feature-frontend-build-bundle-supply-chain-contract]] `FE-OC-018`. hub §13.1에서 도구는 `deferred`. - **error registry 구조·정규화** — [[raw/branch-notes/feature-frontend-error-classification-boundary-contract]] `FE-OC-008`. - **backend authorization·CORS enforcement** — 서버/브라우저 책임. route guard는 authorization control이 아니며(hub §13.2), client validation은 backend validation을 대체하지 않는다. ## 근거 (필수, 최소 1개+) | Source | 정당화하는 결정 | |---|---| | [[raw/official-docs/owasp-html5-storage-xss-spa]] | D4 — 단일 XSS로 localStorage/sessionStorage 전체 탈취·주입 가능하므로 token/secret을 browser storage에 두지 않는다(`OWASP-HTML5-C1`~`C3`). | | [[raw/official-docs/owasp-content-security-policy-cheat-sheet]] | D2·D3 — CSP는 server가 보내는 HTTP response header이고(`OWASP-CSP-C1`), `'unsafe-inline'`/`'unsafe-eval'`이 없으면 inline script·eval이 차단되므로(`OWASP-CSP-C2`·`C3`) bundle이 이를 미의존해야 strict CSP(second layer, `OWASP-CSP-C4`)를 적용할 수 있다. | | [[raw/official-docs/owasp-hsts-cheat-sheet]] | D3 — HSTS 등 security response header는 response header owner(hosting)의 opt-in 결정이며(`OWASP-HSTS-C1`), frontend는 값이 아닌 호환성만 책임진다는 경계의 근거. | | [[raw/official-docs/owasp-logging-cheat-sheet]] | D5 — 다른 trust zone에서 온 event data는 untrusted이며(`OWASP-LOG-C1`) sanitization으로 민감정보를 제거해야 한다(`OWASP-LOG-C3`)는 telemetry/error redaction fixture의 원칙 근거. | | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | D1·D6·D7 — secret 3-way 구분과 name-based 거부(§6.1), bundle=public artifact·source map 미배포(§13.2), secret scan(§13.1), security gate·negative fixture(§15.1·§15.2)의 project decision 근거. | ## TODO - [ ] secret-exclusion: env registry의 name-based 거부(`SECRET`/`PASSWORD`/`PRIVATE_KEY`/`TOKEN`) + source·`dist/` built-asset secret scan fixture 정의 — 등급: `planned` - [ ] injection-lint: `dangerouslySetInnerHTML`·`eval`·dynamic code·untrusted script URL 금지 rule + **금지 rule 1개당 1개**의 deliberately-failing negative fixture(총 3개, D10) — 등급: `planned` - [ ] injection-render fixture(`FE-GATE-006`): 예외 sanitizer 경로 malicious fixture + rendered subtree 에 inline `