작업을 등록하면 작업 레지스트리 파일 .mam/jobs/<job_id>.json 에 MQTT 브로커 비밀번호(broker.password)와 HMAC 서명 키(auth_token), dispatch_token 이 평문으로 저장됩니다. 파일 권한은 0600 이지만 같은 사용자로 실행되는 서브에이전트는 이 파일을 읽을 수 있어, 비밀값이 에이전트 대화 기록과 모델 제공사로 넘어갈 수 있습니다. .agents/MULTI_AGENT_RULES.md §2 의 "전송 데이터에는 비밀번호 등 중요 비밀 정보가 포함되지 않도록 보편화" 규칙과도 어긋납니다.
세부 원인 분석 (Detailed Root Causes)
1. 브로커 비밀번호가 레지스트리에 저장됨
위치: .agents/skills/lib_py/delegation/registry.py 74행(broker_config_from_env().to_registry_block()), 91행("broker": broker), 109행(_atomic_write_record) / .agents/skills/lib_py/delegation/mqtt_common.py 202~210행 to_registry_block() 이 "password": self.password 포함
증상: .mam.env 의 MQTT_PASSWORD 가 작업마다 레지스트리 파일에 복사됨. 재현 워크스페이스에서 .mam/jobs 파일 150개 중 41개에 비밀값 키(auth_token·password 등)가 들어 있었음
설계 의도: registry.py 69~70행 "the registry alone is enough for publish_event.py to connect later"
참고: broker_config_from_job()(mqtt_common.py 261~265행)은 env 기본값 위에 레코드의 non-None 값만 덮어쓰므로, 레코드에 password 를 저장하지 않아도 .mam.env 에서 복원됨
HMAC 검증에 필요해 저장 자체는 필요하지만, 에이전트가 읽을 수 있는 레지스트리 레코드와 같은 파일에 있음
3. 감사 로그와 처리 방식이 다름
delegate_job_logs/ 의 meta.json·events.ndjson 은 _redact_dict(mqtt_common.py 535행)로 마스킹되지만(558행, 633행), 레지스트리 파일에는 적용되지 않음
4. 에이전트 노출 (재현)
create_session.sh --onboard 로 만든 claude 서브에이전트가 onboard 중 .mam/jobs/ 의 작업 기록을 읽고 "MQTT 비밀번호와 auth_token 이 평문으로 들어 있다"고 보고함 → 파일 내용을 읽었으므로 해당 값이 서브에이전트 대화 기록에 포함되었을 수 있음
제안 해결책 (Proposed Fix)
to_registry_block() 에서 password 를 제외(또는 None 저장)하고, 접속 시 broker_config_from_job() 이 env 에서 복원하도록 함 (.mam.env 를 로드하지 않는 실행 경로가 있다면 로드 보장)
auth_token·dispatch_token 은 에이전트가 읽는 레코드와 분리된 파일(예: .mam/secrets/<job_id>.json, 0600)로 옮기거나, 레코드에서 참조만 유지
기존 레코드의 broker.password 를 제거하는 마이그레이션 (선택)
환경 정보 (Environment)
OS: macOS (Darwin 25.6.0)
MAM Version: 4d444ce (main)
브로커: 사설 MQTT (username/password 인증)
## 문제 개요 (Summary)
작업을 등록하면 작업 레지스트리 파일 `.mam/jobs/<job_id>.json` 에 MQTT 브로커 비밀번호(`broker.password`)와 HMAC 서명 키(`auth_token`), `dispatch_token` 이 평문으로 저장됩니다. 파일 권한은 `0600` 이지만 같은 사용자로 실행되는 서브에이전트는 이 파일을 읽을 수 있어, 비밀값이 에이전트 대화 기록과 모델 제공사로 넘어갈 수 있습니다. `.agents/MULTI_AGENT_RULES.md` §2 의 "전송 데이터에는 비밀번호 등 중요 비밀 정보가 포함되지 않도록 보편화" 규칙과도 어긋납니다.
---
## 세부 원인 분석 (Detailed Root Causes)
### 1. 브로커 비밀번호가 레지스트리에 저장됨
* **위치**: `.agents/skills/lib_py/delegation/registry.py` 74행(`broker_config_from_env().to_registry_block()`), 91행(`"broker": broker`), 109행(`_atomic_write_record`) / `.agents/skills/lib_py/delegation/mqtt_common.py` 202~210행 `to_registry_block()` 이 `"password": self.password` 포함
* **증상**: `.mam.env` 의 `MQTT_PASSWORD` 가 작업마다 레지스트리 파일에 복사됨. 재현 워크스페이스에서 `.mam/jobs` 파일 150개 중 41개에 비밀값 키(`auth_token`·`password` 등)가 들어 있었음
* **설계 의도**: `registry.py` 69~70행 "the registry alone is enough for publish_event.py to connect later"
* **참고**: `broker_config_from_job()`(`mqtt_common.py` 261~265행)은 env 기본값 위에 레코드의 non-None 값만 덮어쓰므로, 레코드에 password 를 저장하지 않아도 `.mam.env` 에서 복원됨
### 2. `auth_token`·`dispatch_token` 평문 저장
* **위치**: `registry.py` 75~79행(생성), 97행·103행(저장) / 사용처: `job_subscriber.py` 257행, `publish_event.py` 158행
* HMAC 검증에 필요해 저장 자체는 필요하지만, 에이전트가 읽을 수 있는 레지스트리 레코드와 같은 파일에 있음
### 3. 감사 로그와 처리 방식이 다름
* `delegate_job_logs/` 의 `meta.json`·`events.ndjson` 은 `_redact_dict`(`mqtt_common.py` 535행)로 마스킹되지만(558행, 633행), 레지스트리 파일에는 적용되지 않음
### 4. 에이전트 노출 (재현)
* `create_session.sh --onboard` 로 만든 claude 서브에이전트가 onboard 중 `.mam/jobs/` 의 작업 기록을 읽고 "MQTT 비밀번호와 auth_token 이 평문으로 들어 있다"고 보고함 → 파일 내용을 읽었으므로 해당 값이 서브에이전트 대화 기록에 포함되었을 수 있음
---
## 제안 해결책 (Proposed Fix)
* `to_registry_block()` 에서 `password` 를 제외(또는 `None` 저장)하고, 접속 시 `broker_config_from_job()` 이 env 에서 복원하도록 함 (`.mam.env` 를 로드하지 않는 실행 경로가 있다면 로드 보장)
* `auth_token`·`dispatch_token` 은 에이전트가 읽는 레코드와 분리된 파일(예: `.mam/secrets/<job_id>.json`, `0600`)로 옮기거나, 레코드에서 참조만 유지
* 기존 레코드의 `broker.password` 를 제거하는 마이그레이션 (선택)
## 환경 정보 (Environment)
* OS: macOS (Darwin 25.6.0)
* MAM Version: `4d444ce` (main)
* 브로커: 사설 MQTT (username/password 인증)
main 8e7282c 에 병합되어 해결되었습니다 (v4.4.4, 브랜치 fix/issue-12-8-7).
to_registry_block 이 브로커 password 를 레코드에 쓰지 않고, _atomic_write_record 가 쓰기 시 password 를 제거합니다. 실행 시 MQTT_PASSWORD 는 .mam.env 에서 복원됩니다.
기존 레코드 정리용 registry.py scrub-secrets [--dry-run] 추가 (값이 있는 password 레코드만 lock 아래에서 재기록).
테스트: tests/test_issue12_registry_secrets.py.
리뷰: claude·agy·grok·codex 4인 [VERDICT: PASS].
main `8e7282c` 에 병합되어 해결되었습니다 (v4.4.4, 브랜치 `fix/issue-12-8-7`).
- `to_registry_block` 이 브로커 password 를 레코드에 쓰지 않고, `_atomic_write_record` 가 쓰기 시 password 를 제거합니다. 실행 시 `MQTT_PASSWORD` 는 `.mam.env` 에서 복원됩니다.
- 기존 레코드 정리용 `registry.py scrub-secrets [--dry-run]` 추가 (값이 있는 password 레코드만 lock 아래에서 재기록).
- 테스트: `tests/test_issue12_registry_secrets.py`.
- 리뷰: claude·agy·grok·codex 4인 `[VERDICT: PASS]`.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
문제 개요 (Summary)
작업을 등록하면 작업 레지스트리 파일
.mam/jobs/<job_id>.json에 MQTT 브로커 비밀번호(broker.password)와 HMAC 서명 키(auth_token),dispatch_token이 평문으로 저장됩니다. 파일 권한은0600이지만 같은 사용자로 실행되는 서브에이전트는 이 파일을 읽을 수 있어, 비밀값이 에이전트 대화 기록과 모델 제공사로 넘어갈 수 있습니다..agents/MULTI_AGENT_RULES.md§2 의 "전송 데이터에는 비밀번호 등 중요 비밀 정보가 포함되지 않도록 보편화" 규칙과도 어긋납니다.세부 원인 분석 (Detailed Root Causes)
1. 브로커 비밀번호가 레지스트리에 저장됨
.agents/skills/lib_py/delegation/registry.py74행(broker_config_from_env().to_registry_block()), 91행("broker": broker), 109행(_atomic_write_record) /.agents/skills/lib_py/delegation/mqtt_common.py202~210행to_registry_block()이"password": self.password포함.mam.env의MQTT_PASSWORD가 작업마다 레지스트리 파일에 복사됨. 재현 워크스페이스에서.mam/jobs파일 150개 중 41개에 비밀값 키(auth_token·password등)가 들어 있었음registry.py69~70행 "the registry alone is enough for publish_event.py to connect later"broker_config_from_job()(mqtt_common.py261~265행)은 env 기본값 위에 레코드의 non-None 값만 덮어쓰므로, 레코드에 password 를 저장하지 않아도.mam.env에서 복원됨2.
auth_token·dispatch_token평문 저장registry.py75~79행(생성), 97행·103행(저장) / 사용처:job_subscriber.py257행,publish_event.py158행3. 감사 로그와 처리 방식이 다름
delegate_job_logs/의meta.json·events.ndjson은_redact_dict(mqtt_common.py535행)로 마스킹되지만(558행, 633행), 레지스트리 파일에는 적용되지 않음4. 에이전트 노출 (재현)
create_session.sh --onboard로 만든 claude 서브에이전트가 onboard 중.mam/jobs/의 작업 기록을 읽고 "MQTT 비밀번호와 auth_token 이 평문으로 들어 있다"고 보고함 → 파일 내용을 읽었으므로 해당 값이 서브에이전트 대화 기록에 포함되었을 수 있음제안 해결책 (Proposed Fix)
to_registry_block()에서password를 제외(또는None저장)하고, 접속 시broker_config_from_job()이 env 에서 복원하도록 함 (.mam.env를 로드하지 않는 실행 경로가 있다면 로드 보장)auth_token·dispatch_token은 에이전트가 읽는 레코드와 분리된 파일(예:.mam/secrets/<job_id>.json,0600)로 옮기거나, 레코드에서 참조만 유지broker.password를 제거하는 마이그레이션 (선택)환경 정보 (Environment)
4d444ce(main)main
8e7282c에 병합되어 해결되었습니다 (v4.4.4, 브랜치fix/issue-12-8-7).to_registry_block이 브로커 password 를 레코드에 쓰지 않고,_atomic_write_record가 쓰기 시 password 를 제거합니다. 실행 시MQTT_PASSWORD는.mam.env에서 복원됩니다.registry.py scrub-secrets [--dry-run]추가 (값이 있는 password 레코드만 lock 아래에서 재기록).tests/test_issue12_registry_secrets.py.[VERDICT: PASS].