Repository navigation
fix: Keep URL signing key and API token out of responses and logs - #1508
Merged
Merged
Conversation
Work in progress for apify/ai-team#330, still under review. - get-dataset and get-key-value-store drop urlSigningSecretKey. - apify-api-read and resources/read remove the key from JSON bodies. - resources/read masks the session token in every body. Claude-Session: https://claude.ai/code/session_011ezU64HVKM4BD7jMtSzqag
Work in progress for apify/ai-team#330, still under review. - apify-api-read and resources/read redact the urlSigningSecretKey value instead of removing the key; no parse or re-serialization. - Drop the superseded removal code and its tests. Claude-Session: https://claude.ai/code/session_011ezU64HVKM4BD7jMtSzqag
Part of apify/ai-team#330. - readApiResource logs failed requests (including the signed-link fallback) without the axios request config, which holds the token. - Share one token mask and the plain-error helper between both proxies. - Redact a value with a backslash before a line break. - Docs: redaction applies to JSON bodies decoded with their declared charset; apify-api-read description no longer claims byte-exact bodies. - Drop an unneeded cast and comments that restated the code. Claude-Session: https://claude.ai/code/session_011ezU64HVKM4BD7jMtSzqag
Part of apify/ai-team#330. logHttpError logged the raw error, so an axios error carried its request config, including the Authorization header, into the log for every caller. It now logs a plain copy (name, message, stack, code, type, cause) and still picks the log level from the original error. Claude-Session: https://claude.ai/code/session_011ezU64HVKM4BD7jMtSzqag
Part of apify/ai-team#330. Copy only Error causes, at most three levels deep, so a cyclic or very deep cause chain cannot make the logger throw. Log non-Error values without a synthetic stack or their fields. Claude-Session: https://claude.ai/code/session_011ezU64HVKM4BD7jMtSzqag
Part of apify/ai-team#330. Log a primitive cause as text, as before; still drop object causes, which can hold a request config. Pin the cause depth with a test. Claude-Session: https://claude.ai/code/session_011ezU64HVKM4BD7jMtSzqag
jirispilka
marked this pull request as ready for review
October 8, 2026 20:47
Part of apify/ai-team#330. Remove tests for inputs the API never sends (very deep nesting, bodies past the inline limit, timing), regex cases on invalid JSON, unchanged signed-link log levels, and cause-depth/primitive-cause details. Every key-removal, redaction, token-mask and log-leak test stays and still fails on the old code. Claude-Session: https://claude.ai/code/session_011ezU64HVKM4BD7jMtSzqag
RobertCrupa
approved these changes
Oct 9, 2026
RobertCrupa
left a comment
Contributor
There was a problem hiding this comment.
Looks good! I tested it on my end and no keys or token could be extracted
MQ37
approved these changes
Oct 9, 2026
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.
Why
Found
urlSigningSecretKeyin tool responses. With the key, anyone holding the transcript can sign non-expiring links to the whole storage. The same key also leaked viaresources/readandapify-api-read, and the user's API token leaked viaresources/readand server logs.Part of apify/ai-team#330.
What changed
get-dataset,get-key-value-store"urlSigningSecretKey": "Xq9…"*PublicUrlfields stayresources/read,apify-api-readon storage JSON"urlSigningSecretKey": "Xq9…""urlSigningSecretKey": "[REDACTED]", every other byte unchangedresources/read/v2/browser-info"authorization": "Bearer apify_api_…""authorization": "Bearer [REDACTED]"logHttpError(all callers)config.headers.AuthorizationThe proxies redact instead of removing the key, because removal means re-serializing the JSON. Re-serializing changes formatting and number precision, and a crafted body cost about 1 GB per read. Hosted logs no longer include fields like
status,config.urlorerrno.Notes for reviewers (human-written)
This started as the two-tool fix for (get-dataset, get-key-value-store). While fixing it we found the same key in resources/read and apify-api-read, then the API token in resources/read (/v2/browser-info) and in server logs (logHttpError). In hindsight it should have been several PRs 🤦. Splitting it now costs more than it saves, so it ships as one. Most of the codes are tests only though.
Proof it works
"[REDACTED]"on/v2/datasets/{id},/v2/key-value-stores/{id}and run-storage shortcuts.pnpm run test:integration: the new storage cases pass on stdio, streamable and stateless HTTP.🤖 Generated with Claude Code
https://claude.ai/code/session_011ezU64HVKM4BD7jMtSzqag
Generated by Claude Code