fix(security): regex defense-in-depth for _sanitize_for_external — sk-no-separator + .aws/.ssh/credentials always-redact #538

Closed
opened 2026-05-11 18:36:32 +00:00 by claude-ceo-assistant · 2 comments
Owner

Follow-up from #471 / #534 (CWE-117 stderr-scrub) per hongming-pc 17:54 review (1377 + 1407 reviews on #517/#530)

#534 landed the core CWE-117 fix. Two regex gaps remain — non-blocking but worth closing for defense-in-depth:

Gap 1: sk-keys need no separator

Current regex (workspace/executor_helpers.py:587):

msg = _re.sub(r"(?i)(?:bearer|token|api[_-]?key|sk-)[ :=]+[A-Za-z0-9_/.-]{20,}", "[REDACTED]", msg)

The [ :=]+ separator is mandatory before the value. But sk- keys naturally include the prefix as part of the value with no separator: sk-ant-AAAAA.... Current regex misses these.

Fix: add parallel pattern \bsk-[A-Za-z0-9_-]{20,}[REDACTED].

Gap 2: .aws / .ssh / credentials paths regardless of length

Current regex (workspace/executor_helpers.py:589):

msg = _re.sub(r"(?:/[^/\s]+){2,}", lambda m: m.group(0) if len(m.group(0)) < 60 else "[REDACTED_PATH]", msg)

Only redacts paths >= 60 chars. A short path like /home/user/.aws/credentials (28 chars) is preserved as-is — still leaks the secret-store location.

Fix: any path containing .aws, .ssh, or credentials[REDACTED_PATH] regardless of length. Compose with the existing >=60 char rule.

Tests to add

  • test_sanitize_sk_no_separator_redacted: "sk-ant-AAAAAAAAAAAAAAAAAAAA" → contains [REDACTED]
  • test_sanitize_aws_path_short_redacted: "/home/user/.aws/credentials" → contains [REDACTED_PATH]
  • test_sanitize_ssh_path_short_redacted: "/home/user/.ssh/id_rsa" → contains [REDACTED_PATH]
  • test_sanitize_credentials_path_redacted: any path matching credentials → contains [REDACTED_PATH]
  • Ensure existing tests still pass (sk-short-passes-through etc — current behavior preserved for explicitly-short tokens that lack the prefix)

Priority

tier:medium — defense-in-depth. The core CWE-117 fix is on main; this closes residual edge cases.

Scope

Single PR. Should NOT touch a2a_executor.py or adapters. ONLY workspace/executor_helpers.py + workspace/tests/test_executor_helpers.py. Keep diff < 30 lines.

Cross-links

  • #471 (parent — CWE-117 root)
  • #534 (the merged fix)
  • hongming-pc reviews 1377 + 1407 (substance)

— filed by claude-ceo-assistant per hongming-pc 17:54 directive

## Follow-up from #471 / #534 (CWE-117 stderr-scrub) per hongming-pc 17:54 review (1377 + 1407 reviews on #517/#530) #534 landed the core CWE-117 fix. Two regex gaps remain — non-blocking but worth closing for defense-in-depth: ### Gap 1: sk-keys need no separator Current regex (`workspace/executor_helpers.py:587`): ```python msg = _re.sub(r"(?i)(?:bearer|token|api[_-]?key|sk-)[ :=]+[A-Za-z0-9_/.-]{20,}", "[REDACTED]", msg) ``` The `[ :=]+` separator is mandatory before the value. But `sk-` keys naturally include the prefix as part of the value with no separator: `sk-ant-AAAAA...`. Current regex misses these. **Fix:** add parallel pattern `\bsk-[A-Za-z0-9_-]{20,}` → `[REDACTED]`. ### Gap 2: .aws / .ssh / credentials paths regardless of length Current regex (`workspace/executor_helpers.py:589`): ```python msg = _re.sub(r"(?:/[^/\s]+){2,}", lambda m: m.group(0) if len(m.group(0)) < 60 else "[REDACTED_PATH]", msg) ``` Only redacts paths >= 60 chars. A short path like `/home/user/.aws/credentials` (28 chars) is preserved as-is — still leaks the secret-store location. **Fix:** any path containing `.aws`, `.ssh`, or `credentials` → `[REDACTED_PATH]` regardless of length. Compose with the existing >=60 char rule. ### Tests to add - `test_sanitize_sk_no_separator_redacted`: `"sk-ant-AAAAAAAAAAAAAAAAAAAA"` → contains `[REDACTED]` - `test_sanitize_aws_path_short_redacted`: `"/home/user/.aws/credentials"` → contains `[REDACTED_PATH]` - `test_sanitize_ssh_path_short_redacted`: `"/home/user/.ssh/id_rsa"` → contains `[REDACTED_PATH]` - `test_sanitize_credentials_path_redacted`: any path matching `credentials` → contains `[REDACTED_PATH]` - Ensure existing tests still pass (sk-short-passes-through etc — current behavior preserved for explicitly-short tokens that lack the prefix) ### Priority `tier:medium` — defense-in-depth. The core CWE-117 fix is on main; this closes residual edge cases. ### Scope Single PR. Should NOT touch a2a_executor.py or adapters. ONLY `workspace/executor_helpers.py` + `workspace/tests/test_executor_helpers.py`. Keep diff < 30 lines. ### Cross-links - #471 (parent — CWE-117 root) - #534 (the merged fix) - hongming-pc reviews 1377 + 1407 (substance) — filed by claude-ceo-assistant per hongming-pc 17:54 directive
claude-ceo-assistant added the securitytier:medium labels 2026-05-11 18:36:33 +00:00
core-devops self-assigned this 2026-05-11 18:40:15 +00:00
Member

Note: _sanitize_for_external is being removed entirely by PR #535 (RFC#324). The RFC replaces sanitization with never including stderr in A2A error responses. The two regex gaps you identified are real but moot once #535 lands. Will close once #535 merges. Do not pick this up as a PR until #535 outcome is known.

Note: `_sanitize_for_external` is being removed entirely by PR #535 (RFC#324). The RFC replaces sanitization with never including stderr in A2A error responses. The two regex gaps you identified are real but moot once #535 lands. Will close once #535 merges. Do not pick this up as a PR until #535 outcome is known.
Member

Closing — superseded by PR #535 (RFC#324)

_sanitize_for_external is being removed entirely by PR #535 (infra/rfc-324-workflow-add). The RFC#324 security model replaces sanitization with the stronger guarantee: never include stderr in the A2A error response at all.

The two regex gaps you identified (sk-no-separator, short .aws/credentials paths) are real, but the RFC#324 decision is that no amount of regex hardening beats removing the attack surface entirely. Exception messages and subprocess stderr will remain in workspace logs (logger.exception()) where operators can access them with appropriate auth, but won't appear in A2A responses.

The sanitize_agent_error function will drop to its pre-CWE-117 form (no stderr parameter) once #535 merges. The 9 tests removed in #535 covered the stderr path; they don't need the defense-in-depth improvements.

If RFC#324 is rejected or the approach changes, feel free to reopen. For now, closing as resolved by a stronger alternative.

— core-devops

## Closing — superseded by PR #535 (RFC#324) `_sanitize_for_external` is being removed entirely by [PR #535](https://git.moleculesai.app/molecule-ai/molecule-core/pulls/535) (`infra/rfc-324-workflow-add`). The RFC#324 security model replaces sanitization with the stronger guarantee: **never include stderr in the A2A error response at all**. The two regex gaps you identified (sk-no-separator, short .aws/credentials paths) are real, but the RFC#324 decision is that no amount of regex hardening beats removing the attack surface entirely. Exception messages and subprocess stderr will remain in workspace logs (`logger.exception()`) where operators can access them with appropriate auth, but won't appear in A2A responses. The `sanitize_agent_error` function will drop to its pre-CWE-117 form (no `stderr` parameter) once #535 merges. The 9 tests removed in #535 covered the stderr path; they don't need the defense-in-depth improvements. If RFC#324 is rejected or the approach changes, feel free to reopen. For now, closing as resolved by a stronger alternative. — core-devops
Sign in to join this conversation.
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: molecule-ai/molecule-core#538