Skip to content

fix(security): JWT secret fail-closed + MS Project XML ReDoS removal - #387

Closed
seonghobae wants to merge 1 commit into
fix/security-hono-csv-hardeningfrom
fix/jwt-fail-closed-xml-redos
Closed

fix(security): JWT secret fail-closed + MS Project XML ReDoS removal#387
seonghobae wants to merge 1 commit into
fix/security-hono-csv-hardeningfrom
fix/jwt-fail-closed-xml-redos

Conversation

@seonghobae

@seonghobae seonghobae commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Summary

Production auth must not mint JWTs with a hardcoded or weak secret.

  1. JWT fail-closed (server/auth.mjs): startup throws unless SCOPEWEAVE_JWT_SECRET is a string with ≥32 non-whitespace characters and is not an unexpanded Compose literal (\${SCOPEWEAVE_JWT_SECRET…}).
  2. Compose/Docker: remove insecure-dev-secret-CHANGE-ME default; document required secret.
  3. MS Project XML ReDoS: parseMsProjectXml uses linear indexOf/slice instead of new RegExp(name).
  4. Tests: tests/api/auth-secret.test.mjs (wired into test:api); smoke/ratelimit/cloud e2e use a 32-char test secret; unit case for regex-metachar task names.
  5. Docs: README / docs/deploy.md / CLAUDE.md match the shipped contract.

Supersedes

Closes the same gap as open #329 with a clean reimplementation on current develop (no stale base). #329 can be closed after this opens.

Related

Verification

  • npm run test:unit
  • npm run test:api ✅ (auth-secret + smoke + ratelimit)

Summary by CodeRabbit

  • 보안 개선

    • JWT 시크릿을 필수로 변경하고, 공백 제외 32자 미만이거나 누락된 경우 서버 시작을 차단합니다.
    • 안전하지 않은 기본 시크릿을 제거했습니다.
    • XML 작업 이름의 특수 문자가 올바르게 처리되도록 개선했습니다.
  • 문서

    • 로컬 개발 및 Docker 실행 시 시크릿 생성·설정 방법과 필수 조건을 명확히 안내합니다.
  • 테스트

    • JWT 시크릿 검증, Docker 설정, XML 특수문자 처리에 대한 테스트를 추가·보강했습니다.

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

이 PR은 SCOPEWEAVE_JWT_SECRET 검증을 경고 방식에서 시작 실패 방식으로 강화하고, docker-compose.yml의 불안전한 기본값을 제거하며, 관련 문서와 테스트를 업데이트한다. 별개로 cloud-sync.js의 XML 태그 추출 함수를 정규식 기반에서 문자열 인덱스 기반으로 교체하여 ReDoS 위험을 제거한다.

Changes

JWT 시크릿 필수화

Layer / File(s) Summary
시크릿 검증 로직 강화
server/auth.mjs
환경 변수 필수 요구, 문자열 타입 검증, 공백 제외 최소 32자 길이 검증, 미확장 리터럴 검출을 추가하고, 검증 실패 시 에러를 발생시켜 시작을 중단한다.
배포 설정 및 문서 업데이트
docker-compose.yml, README.md, docs/deploy.md, Dockerfile.server, CLAUDE.md
불안전한 기본값을 제거하고, 문서의 "필수(프로드만)" 표기를 조건 없는 "필수"로 변경하며, 최소 문자 요구사항과 시작 실패 동작을 명시한다.
시크릿 검증 테스트 추가 및 기존 테스트 갱신
tests/api/auth-secret.test.mjs, package.json, tests/api/ratelimit.test.mjs, tests/api/smoke.mjs, tests/e2e/cloud.spec.js
약한 시크릿과 유효한 시크릿의 시작 동작을 검증하는 테스트를 추가하고, test:api 스크립트에 포함시키며, 기존 테스트의 시크릿 값을 32자 16진수 문자열로 갱신한다.

XML 태그 추출 안전성 개선

Layer / File(s) Summary
tag 헬퍼 함수 리팩토링 및 테스트
cloud-sync.js, tests/unit/msproject.test.mjs
tag 함수를 indexOf/slice 기반 문자열 추출로 재작성하여 동적 정규식 생성을 제거하고, 정규식 특수 문자가 포함된 작업 이름을 리터럴로 처리하는지 확인하는 테스트를 추가한다.

Estimated code review effort: 2 (Simple) | ~15 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Test as auth-secret.test.mjs
  participant ChildProcess
  participant AuthModule as auth.mjs
  Test->>ChildProcess: SCOPEWEAVE_JWT_SECRET 설정 후 실행
  ChildProcess->>AuthModule: 모듈 로드
  AuthModule->>AuthModule: 타입/길이/리터럴 검증
  alt 검증 실패
    AuthModule-->>ChildProcess: Error 발생, 종료 코드 비0
  else 검증 성공
    AuthModule-->>ChildProcess: 정상 시작, 종료 코드 0
  end
  ChildProcess-->>Test: 종료 코드 및 stderr 반환
Loading

Possibly related PRs

  • ContextualWisdomLab/scopeweave#364: 두 PR 모두 cloud-sync.js의 parseMsProjectXml 내 tag() 헬퍼 함수를 수정하여 동적 RegExp 기반 XML 추출을 변경한다.
  • ContextualWisdomLab/scopeweave#365: 두 PR 모두 cloud-sync.js의 tag 추출 헬퍼를 동적 정규식 파싱에서 인덱스 기반 문자열 추출로 교체한다.
  • ContextualWisdomLab/scopeweave#371: 두 PR 모두 동일한 cloud-sync.js XML 태그 파싱 헬퍼를 수정하여 동적 정규식 추출을 인덱스 기반 파싱으로 교체한다.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 JWT 시크릿의 fail-closed 검증과 MS Project XML ReDoS 제거라는 PR의 두 가지 주요 변경을 정확하고 간결하게 설명합니다.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/jwt-fail-closed-xml-redos

Comment @coderabbitai help to get the list of available commands.

- server/auth.mjs: refuse startup when SCOPEWEAVE_JWT_SECRET is missing,
  <32 non-whitespace chars, or an unexpanded compose literal (no more
  hardcoded dev-insecure-secret fallback)
- docker-compose.yml / Dockerfile.server: drop insecure default secret
- cloud-sync parseMsProjectXml: replace dynamic RegExp tag parse with
  indexOf/slice (eliminates ReDoS / Semgrep non-literal-regexp surface)
- Add tests/api/auth-secret.test.mjs; wire into test:api; strengthen
  MS Project unit case for regex-metachar task names
- Docs (README, deploy, CLAUDE): required secret contract

Supersedes open PR #329 with a clean develop rebase of the same contract.
@seonghobae

Copy link
Copy Markdown
Contributor Author

Stack note: rebased onto fix/security-hono-csv-hardening (#386) and retargeted base so this lands after the hono/CSV hardening PR.

Merge order: #386#387.

Local verification on this head:

  • npm run test:unit
  • npm run test:api (incl. auth-secret) ✅

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/unit/msproject.test.mjs`:
- Around line 58-62: 보강된 테스트가 동적 정규식 제거를 실제로 검증하지 못하고 있습니다.
tests/unit/msproject.test.mjs의 parseMsProjectXml 테스트에서 정규식 메타문자를 XML 본문이 아닌 tag의
name 인자로 전달하는 경계를 직접 검증하도록 수정하고, 작업 이름 보존 검증과 ReDoS 회귀 검증을 분리하세요.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d74a480f-d313-4d19-8be3-56dfa64ded70

📥 Commits

Reviewing files that changed from the base of the PR and between a756b7e and 8bdad23.

📒 Files selected for processing (13)
  • CLAUDE.md
  • Dockerfile.server
  • README.md
  • cloud-sync.js
  • docker-compose.yml
  • docs/deploy.md
  • package.json
  • server/auth.mjs
  • tests/api/auth-secret.test.mjs
  • tests/api/ratelimit.test.mjs
  • tests/api/smoke.mjs
  • tests/e2e/cloud.spec.js
  • tests/unit/msproject.test.mjs

Comment on lines +58 to +62
const literalRegexText = parseMsProjectXml(
'<Project><Tasks><Task><UID>6</UID><Name>Regex [.*+?] text</Name><OutlineLevel>1</OutlineLevel></Task></Tasks></Project>',
);
assert.equal(literalRegexText[0].phase, 'Regex [.*+?] text', 'tag extraction treats task content as literal text');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

ReDoS 회귀 테스트가 실제 변경을 검증하도록 보강하세요.

현재 [.*+?]는 XML <Name> 본문에 있습니다. 이 문자열은 tagname 인자에 전달되지 않습니다. 따라서 기존 new RegExp(...) 구현도 이 테스트를 통과할 수 있습니다. 현재 테스트는 작업 이름 보존만 검증하며 동적 정규식 제거를 검증하지 않습니다. name이 외부 입력이 될 수 있다면 해당 경계를 직접 테스트하세요. 그렇지 않다면 테스트 목적을 작업 이름 보존으로 명확히 하고 ReDoS 검증은 별도로 추가하세요.

제공된 변경 설명의 기존 new RegExp(...) 동작과 현재 테스트 입력을 비교한 판단입니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/msproject.test.mjs` around lines 58 - 62, 보강된 테스트가 동적 정규식 제거를 실제로
검증하지 못하고 있습니다. tests/unit/msproject.test.mjs의 parseMsProjectXml 테스트에서 정규식 메타문자를
XML 본문이 아닌 tag의 name 인자로 전달하는 경계를 직접 검증하도록 수정하고, 작업 이름 보존 검증과 ReDoS 회귀 검증을
분리하세요.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Converted to draft and cancelled queued CI so org runners prioritize merge-first #386. Will re-request CI after #386 lands (or when runners free).

@seonghobae

Copy link
Copy Markdown
Contributor Author

Superseded: JWT fail-closed + MS Project XML ReDoS folded into #386 (single security PR). Close as duplicate of the consolidated train.

@seonghobae seonghobae closed this Jul 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant