security(logger): contain credential-bearing config in 4xx/5xx request-body logs (PEN-2843) - #1583
Merged
Merged
Conversation
…t-body logs (PEN-2843) customProps logs the whole request body on every 4xx/5xx. redactSensitive masked only exact-match key names, and PATCH /agents/:id and the hire_agent approval path both accept adapterConfig.env in that body — so a routine validation rejection wrote those values verbatim to stdout and the log file. A name denylist cannot close this: the leaves under env are arbitrary per-agent variable names, so no list can enumerate them. Invert the burden instead — name the few containers whose contents are secret by construction and mask every scalar leaf beneath them at any depth, regardless of name. Key names are preserved so a 4xx log still records which variables were set. Also handles the two shapes that have bypassed walkers on this series before: array-shaped containers (a walk guarding only plain objects recurses past them) and scalar/JSON-string-shaped containers (returned verbatim). Refs PEN-2370 Signed-off-by: Cto <cto@paperclip.blockcast.net>
Author
Author
There was a problem hiding this comment.
Ally — Consolidated PR Review
Lenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex.
Reviewed head: a63ff7b
Critical Issues (0)
Important Issues (0)
Suggestions (0)
Strengths
- The redaction policy correctly handles credential-bearing containers by exact key, preserving diagnostic names while masking scalar leaves.
- Array and scalar/string-shaped containers are covered explicitly, and the implementation retains the existing depth cap behavior.
- Tests cover deep nesting, bypass-prone shapes, and look-alike keys to constrain overreach.
Recommended Action
- No Critical or Important issues found. The App-authored PR is reviewed as a formal comment at the exact head.
14 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Thinking Path
Linked Issues or Issue Description
No GitHub issue exists; the finding is tracked in Paperclip. Summary, following the bug template:
What happened.
customPropsinserver/src/middleware/logger.tslogsreqBodyon every response>= 400.redactSensitivemasks only keys present in an exact-matchSENSITIVE_KEYSset.env,adapterConfig,runtimeConfigandmcpServersare absent from it, and a real variable name such asOPENAI_API_KEYdoes not match either (the set holds the literalsapi_key/apikey; it does not substring-match). A request to a route that acceptsadapterConfig—PATCH /agents/:id, or thehire_agentapproval payload — which returns any 4xx therefore emits those values in the clear.Expected. Credential material never reaches a log line.
Impact. Log output is readable by anything with log access, including the read-only Kubernetes grant's
pods_log. No attacker is required: a routine validation rejection is sufficient.Not reproduced against live data. No pod was probed and no pod log was read — reading it is the exposure. The finding is established from source and pinned by unit tests over synthetic values.
What Changed
server/src/middleware/redact-sensitive.tsSENSITIVE_CONTAINER_KEYS—adapterConfig,runtimeConfig,env,mcpServers,headers— keys whose entire subtree is credential material by construction.redactContainer, which masks every scalar leaf beneath such a key at any depth while preserving structure and key names, so the log still says which variables were set.MAX_DEPTHcap, so the cycle and depth-cap contracts are unchanged.server/src/__tests__/redact-sensitive.test.ts— six tests covering value-elision-with-name-preservation, deep nesting, the array shape, the string shape,mcpServers/headersvalues the scalar rules miss, and an over-reach guard.Verification
Fail-first confirmed. 5 of the 6 new tests fail on unfixed
master, with the planted secret visible in the failure text — e.g.expected '{"adapterConfig":[{"env":{"K":"array-secret"}}]}' not to contain 'array-secret'.The 6th is an over-reach guard (
environment,configVersion,envoymust stay untouched) and correctly passes on both trees.One test is worth calling out because it initially proved nothing: the
mcpServers/headerscase first used aurlkey and anAuthorizationheader, and passed on unfixed code — it was being carried by the existing URL-part stripper and the existingauthorizationdenylist entry, not by the new rule. It was rewritten to use a token in a path segment under a non-urlish key and a vendor-specific header name, so it now genuinely exercises the container path and fails without the fix.Blast radius.
middleware/redact-sensitive.tshas exactly one production importer,middleware/logger.ts. This changes log output only; no response path is affected.Risks
Low, and bounded to log output.
environment,envoyandconfigVersionare unaffected; pinned by a test.headersis the broadest entry. Included deliberately — credential-bearing MCP headers are door fix(agents): drop redacted env sentinel ("***") on PATCH/POST round-trips #8's material — and it only ever affects aheadersobject inside a logged request body.Model Used
claude-opus-5[1m]— 1M context, extended thinking, agentic tool use (repository read/write, test execution, GitHub API).Checklist
packages/plugins/sandbox-providers/kubernetes/src/sensitive-env-guard.ts, a different file in a different package; no overlapFixes: #/Closes #/Refs #OR (b) described the issue in-PR following the relevant issue templatea63ff7bd3: 20 SUCCESS, 0 failing, 1 SKIPPED (Storybook visual regression);mergeStateStatusCLEANGreptile is 5/5— not applicable on this repository. Greptile does not reviewBlockcast/paperclip; the sibling PRs in this same series (security(mcp-gateway): let a grant enumerate the tools it exposes (PEN-2735) #1573, fix(approvals): gate hire_agent embedded agent config on agent_config:read #1574, security(portability): redact agent credentials on the company export path (PEN-2778) #1578) each merged withallyblockcastas the only reviewer. Ally's review at this exact head returned 0 Critical / 0 Important / 0 Suggestions.